Packaging and deployment
Oganesson supports three outputs: a .og/ directory for local serving, one self-contained executable for deployment, and an ejected Go module for custom server code.
Build directory
og build ./project
og serve -addr :3000 ./projectThe project receives a .og/ directory containing its server program, browser assets, public files, build metadata, prerendered entries, traced files, and application license notices. The directory is replaced on every build.
This form is useful for inspection and local validation. It cannot run project-owned native Go modules, because they are not compiled into the stock og serve executable.
Self-contained executable
og build -o ./my-app ./project
./my-app -addr :3000Oganesson appends the .og/ payload to a runtime executable as a zip followed by an OGPAYLD1 trailer. At startup the executable discovers its own payload and becomes the application server.
For the runtime, Oganesson prefers a slim serve-only binary: when the Go toolchain is on PATH it compiles a runtime that links only what serves the app, leaving out og's build-time toolchain (chiefly the TypeScript compiler), which makes the artifact substantially smaller. Without Go it falls back to copying the whole og and prints a note; the application is identical either way, only larger. Choose a specific toolchain with -go (a path or a name on PATH) or OG_GO. A released og builds the slim runtime from the module proxy with no checkout; an unpublished (locally built) og needs its source, given with -og-source or OG_SOURCE, and copies the full og when neither is set.
The artifact contains all framework server code, browser assets, public files, prerendered entries, Web/Node compatibility code, JavaScript engine, image codecs, SQLite, and notices required by the application. It does not require a sidecar node_modules tree.
The executable is replaced atomically when rebuilt, so a failed write does not damage the previous artifact and a running executable is never modified in place.
Cross-compilation
Name the target with -target goos/goarch:
og build -o ./my-app -target linux/arm64 ./projectWith the Go toolchain on PATH, Oganesson cross-compiles the slim runtime for the target directly (it is pure Go), so no prebuilt runtime is needed. An unpublished og still needs its source for this; pass -og-source or set OG_SOURCE.
Without Go, supply a runtime built for the target. Build one and pass it with -runtime:
scripts/build-og.sh ./og-linux-arm64 linux/arm64
og build -o ./my-app -target linux/arm64 -runtime ./og-linux-arm64 ./project-runtime is copied verbatim (no slim rebuild). Without it, Oganesson looks in the runtime cache:
<UserCacheDir>/oganesson/runtimes/<source-id>/og-<goos>-<goarch>If the file is absent, the error prints the exact scripts/build-og.sh command needed to create it. Oganesson rejects a runtime that:
- targets another OS or architecture;
- is not the
ogprogram; - was built with CGO; or
- was stamped from a different source revision.
Projects with native Go modules always compile their own target runtime (which needs Go) and cannot use -runtime. Oganesson also builds a temporary host runtime to prerender with those Go modules during a cross build.
Ejected Go module
Use ejecting when you need Go HTTP routes, Go middleware, custom build/signing control, or direct runtime registration:
og build \
-eject ./my-app-server \
-og-source /path/to/oganesson \
./projectThe directory contains:
| Path | Purpose | Re-eject behavior |
|---|---|---|
app/ | Build output embedded with go:embed. | Replaced. |
main.go | Server flags, signals, notices, and app.Serve. | Preserved after first creation. |
wrap.go | User-owned HTTP wrapper, initially with GET /healthz. | Preserved. |
go.mod | Oganesson dependency and replacements. | Preserved. |
natives_gen.go | Registration for project-owned Go modules, when present. | Regenerated. |
README.md | Build instructions for the ejected module. | Regenerated. |
THIRD_PARTY_NOTICES.txt | Oganesson and application notices. | Regenerated. |
Oganesson refuses to eject into a non-empty directory that does not look like a previous ejected output. This protects unrelated files. Re-ejecting preserves the files intended for user changes.
Add routes or middleware in wrap.go, then build as a normal Go program:
cd my-app-server
go mod tidy
CGO_ENABLED=0 go build -trimpath -tags nodynamic -o my-app .
./my-app -addr :3000nodynamic keeps WebP support on the pure-Go path and matches release builds. Until Oganesson is published as a Go module, the ejected module requires -og-source and a checkout with TypeScript-Go synchronized.
Containers
A packaged binary can run in a minimal image:
FROM gcr.io/distroless/static-debian12:nonroot
COPY my-app /my-app
EXPOSE 3000
ENTRYPOINT ["/my-app"]Cross-build the executable for the image platform first. Distroless is useful because it includes CA certificates and time-zone data. scratch also works if the application does not need them, or if you copy the required certificate and zoneinfo files into the image.
Mount host directories and pass absolute paths for persistent SQLite or files. The packaged virtual filesystem's writable overlay is memory-only.
Runtime configuration
PORT=8080 ./my-app
./my-app -addr 127.0.0.1:8080
./my-app -licensesThe server binds all interfaces on port 3000 by default. Prefer an explicit address when local-only binding is required. Application environment variables are read normally by server code.
Horizontal replicas do not share ISR entries, Cache Components data, optimized images, og:kv, or virtual filesystem writes. Use external shared services when replicas must observe the same state.
License notices
og licenses prints the licenses compiled or embedded into Oganesson. During an application build, Oganesson also inspects esbuild inputs and build-host asset reads to collect notices for npm packages whose code, CSS, or fonts ship in the artifact. Downloaded Google Fonts receive an attribution notice.
Use my-app -licenses for a packaged binary. Ejected modules also include a THIRD_PARTY_NOTICES.txt file.
The collector intentionally excludes build-time-only tools, but it cannot infer every legal relationship. Review the output before distribution, especially for copied files, generated assets, and framework-specific static build paths.