#+TITLE: Quick start #+DESCRIPTION: A working site in two commands, then your own writing, then your own design. #+LEDE: Five minutes from nothing to a site that reloads as you type. * Two commands #+BEGIN_SRC sh orgo init my-site orgo serve my-site -o _site #+END_SRC Open [[http://127.0.0.1:3000][127.0.0.1:3000]]. Edit =my-site/index.org= in your editor, save, and the page reloads on its own. =init= writes only files that do not already exist, so running it inside a directory that already has content is safe and additive. ** What init created #+BEGIN_EXAMPLE my-site/ orgo.toml every setting, commented — all at their defaults but `theme` index.org the home page blog/first-post.org a post, to show the collection working templates/ base.html the page layout — edit this list.html the blog index tags.html the tag index feed.xml an RSS feed #+END_EXAMPLE * Adapting it to org files you already have You do not need =init=, a config file, or templates. Every command takes the same two paths: #+BEGIN_SRC sh orgo serve -o #+END_SRC ** SOURCE is the URL root This is the one thing worth getting right, and it is not "the project directory" — it is *the directory whose contents should sit at the top of your site*. A file at =SOURCE/blog/post.org= is published at =/blog/post.html=. So if your writing lives in a =content/= subdirectory, point at =content/=, not at the repository around it: #+BEGIN_SRC sh cd ~/my-site orgo serve content -o _site # → /blog/post.html #+END_SRC Pointing one level too high still builds, which is what makes it worth saying out loud. It just builds the wrong site: #+BEGIN_SRC sh orgo serve . -o _site # → /content/blog/post.html #+END_SRC Every URL gains a =/content/= prefix, and every non-org file in the repository — =README.md=, build scripts, licence files — is copied into the output as a site asset. If you see either symptom, you picked the directory above the one you meant. ** Common layouts | Your files | Command | |------------+---------| | =~/notes/*.org= | =orgo serve ~/notes -o /tmp/notes-site= | | =my-site/content/**/*.org= | =cd my-site && orgo serve content -o _site= | | =my-site/*.org= at the top level | =cd my-site && orgo serve . -o _site= | | Org files scattered in a code repo | Do not. Copy or symlink the ones you publish into one directory. | ** OUTPUT can live inside the source =orgo serve . -o _site= is fine: the output directory is recognised and skipped, so the build never copies its own output back into itself. Nothing dot-prefixed is published either, so =.git= stays out of a site built from a repository root. ** Where config and templates go Both live in the *source* directory — =SOURCE/orgo.toml= and =SOURCE/templates/= — and neither is published. If you would rather keep the config elsewhere, name it: #+BEGIN_SRC sh orgo serve content -o _site --config config/orgo.toml #+END_SRC ** A worked example A repository laid out as =content/= (org files), =theme/= (unrelated), =build.py=: #+BEGIN_SRC sh cd ~/my-site # What is actually in there, before trusting anything with it. orgo audit content # Build it somewhere disposable and look. orgo serve content -o /tmp/preview # Happy with it? Build for real, failing on broken links. orgo build content -o _site --strict #+END_SRC The audit reports which org constructs appear, how often, and whether each is supported — names, counts and line numbers only, never your text. See [[file:guide/09-auditing.org][Auditing a corpus]]. Nothing in your files has to change. With no config you get a complete site: a built-in layout, navigation across your top-level pages, and syntax highlighting. * Write a page Any =.org= file under the source directory becomes a page at the matching path. =notes/rust/borrowing.org= becomes =notes/rust/borrowing.html=. #+BEGIN_SRC org ,#+TITLE: Borrowing ,#+DATE: <2026-02-02 Mon> ,#+FILETAGS: :rust:notes: ,#+DESCRIPTION: How the borrow checker thinks about lifetimes. An opening paragraph, which becomes the excerpt in listings when there is no description. ,* A heading Ordinary org: *bold*, /italic/, ~code~, [[https://orgmode.org][links]], and lists. ,#+BEGIN_SRC rust fn main() {} ,#+END_SRC #+END_SRC The keywords are all optional. =#+TITLE:= names the page, =#+DATE:= orders it in listings, =#+FILETAGS:= groups it on tag pages, and =#+DESCRIPTION:= is its summary. ** Control the URL By default the filename decides the URL. =#+SLUG:= overrides it, which is how a date-prefixed filename becomes a clean address: #+BEGIN_SRC org ,#+TITLE: Borrowing ,#+SLUG: borrowing-explained #+END_SRC =2026-02-02-borrowing.org= now publishes as =borrowing-explained.html=. ** Keep something unfinished out of the build #+BEGIN_SRC org ,#+DRAFT: t #+END_SRC The page is not written, and does not appear in listings or navigation. Preview it while you work with =--drafts=: #+BEGIN_SRC sh orgo serve my-site -o _site --drafts #+END_SRC * Change the design Everything visual lives in =templates/base.html=. It is an ordinary [[https://docs.rs/minijinja][minijinja]] (Jinja2) template, and replacing it replaces the whole layout: #+BEGIN_SRC html {{ page.title }} — {{ site.title }}

{{ page.title }}

{{ body | safe }} #+END_SRC =root= is the =../= prefix back to the site root, so the same template works at any depth. Any other file in the source directory — =style.css=, images, fonts — is copied to the output untouched. Editing a template rebuilds every page that uses it, so the browser reloads while you are still looking at it. The full list of variables is in [[file:guide/04-templates.org][Templates]]. * Add a blog index Listing pages have no source file; they are declared in =orgo.toml=: #+BEGIN_SRC toml [[collections]] source = "blog" output = "blog/index.html" template = "list.html" title = "Blog" sort = "date" order = "desc" nav = true #+END_SRC That is also how you get tag pages, pagination and an RSS feed — same mechanism, more settings. See [[file:guide/03-collections.org][Collections]]. * Build for real #+BEGIN_SRC sh orgo build my-site -o _site --strict #+END_SRC =--strict= turns broken internal links and parse diagnostics into a non-zero exit, which is what you want in CI. Deployment is just copying =_site= somewhere; see [[file:guide/10-deploying.org][Deploying]]. * Next - [[file:guide/01-cli.org][Command reference]] — every command and flag. - [[file:guide/02-configuration.org][Configuration]] — every setting in =orgo.toml=. - [[file:guide/05-org-support.org][Org support]] — exactly which org syntax is handled.