As of 2023 the answers suggesting to use \AtBeginDocument might be outdated. In fact, clsguide.pdf has on p. 16
The \AtBeginDocument hook should not be used for code that does any typesetting since the typeset result would be unpredictable.
Simplifying, the code \begin{document} expands to
\UseHook{env/document/before}
\begingroup
\def\@currenvir{document}
\UseHook{env/document/begin}
\UseOneTimeHook{begindocument/before}%
% ... global option check, size setting, aux file, font setup
\normalsize
\everypar{}%
% ... spacefactor codes, language, metadata, page size
\UseOneTimeHook{begindocument}% <--- \AtBeginDocument goes in here
% ... other settings
\UseOneTimeHook{begindocument/end}%
\ignorespaces
I've marked where the content of \AtBeginDocument is inserted. While font sizes have been set up and \everypar has been "cleared" such that it doesn't throw the Missing \begin{document} error, other stuff goes on and, as the official guide tells, the result might be unpredictable. (Subjunctive: clearly you might also get lucky.) The very last hook executed by \begin{document}, just before \ignorespaces, is begindocument/end (see also lthooks-doc.pdf, p.25). Material to be typeset should thus come into this hook:
\documentclass{article}
\AddToHook{begindocument/end}{Hello world!\par}
\begin{document}
Hello world.
\end{document}

With a format later than 2020-10-01, etoolbox's own \AfterEndPreamble is simply mapped into \AddToHook{begindocument/end}. With older formats it can still be used safely, because the used hook is added at the very end of \document by something like this:
\edef\document{\unexpanded\expandafter{\document Hello world!\par}}
Doing this yourself is clearly evil. Fluffy little bunnies will die horribly any time you do so, unless you are a dark TeX wizard/witch who really knows what he/she is doing.
latex-generaltag (and alsolatex3) is for questions about LaTeX and the LaTeX project in general. A good example is Difference between LaTeX, LaTeX2e, LaTeX3?. Your question is about a specific task and therefore should not be tagged with it. – Martin Scharrer Mar 24 '11 at 09:56