Dev Container Concept
This document explains the Dev Containers concept in general, then describes the specific Dev Container Niksphere provides for App development, and how it is used from VS Code and from GitHub Codespaces. It is the deep dive behind the Local Container and Cloud Container rows in Developer Environment Topologies — read that page first for how this topology compares to running everything natively or against Niksphere Cloud.
1. What Is a Dev Container?
A Dev Container is a development environment fully described as code, using the open Dev Containers specification originally published by Microsoft and now implemented by multiple independent tools — not just VS Code. Instead of a setup guide that a developer follows by hand (install this compiler, that database, this exact CLI version), the environment is defined once in a devcontainer.json file checked into the project's repository, and every tool that understands the specification can read it and produce an identical, ready-to-use container.
A devcontainer.json describes three things:
- What image the container runs. Either a plain base
image, aDockerfileto build one, or adockerComposeFilewhen the environment needs more than one container (e.g. an application container plus a database). - What tooling gets layered onto that image, via Dev Container Features — small, independently versioned, composable install scripts (e.g. "install the AWS CLI", "install Node.js 20") that any base image can pick up without needing its own bespoke
Dockerfilelogic. - How the editor should behave once attached — which extensions to install, which settings to apply, which ports to forward, and lifecycle commands to run at specific points (
postCreateCommand,postStartCommand, etc.).
Because this definition is versioned alongside the code, every developer working on the same repository — and every CI job, and every cloud-hosted instance — gets the exact same environment, without a manually maintained onboarding document drifting out of date.
2. The Niksphere Dev Container
A Niksphere App's Dev Container is defined by a devcontainer.json and docker-compose.yml pair that together define a three-container development stack. Where exactly that pair lives depends on the repository layout — see the note on monorepos in Section 4 for the convention used when several Apps share one repository.
appis the container the editor actually attaches to. It starts from a plain base image (e.g.mcr.microsoft.com/devcontainers/base:bookworm) and gets the Niksphere CLI and VS Code Extension layered onto it via two published Dev Container Features,ghcr.io/niksphere/niksphere-devcontainer/cliandghcr.io/niksphere/niksphere-devcontainer/vscode-extension. Because these are independently published Features rather than logic baked into each App project's ownDockerfile, a fix or a new CLI release only needs to be published once and every project's Dev Container picks it up on its next rebuild. Both Features accept achanneloption (stableorinsider), matching the Niksphere CLI's own release channels.engineruns the official Engine Docker Container image,ghcr.io/niksphere/niksphere-engine, unmodified — the same image used for self-hosted production deployments. It sharesapp's network namespace (network_mode: service:app) so thatlocalhostmeans the same address insideapp, insideengine, and — via the editor's own local port forwarding — in a browser on the host. This matters specifically for the OAuth authorization flow (nik env auth login), which opens a browser page on the host that must be able to reach the Engine at the same address the CLI itself uses.dbruns the stockpostgres:15-alpineimage backing the Engine, using the driver and connection settings described in Engine Database Concept.
A devcontainer-lock.json file, generated automatically and committed alongside devcontainer.json, pins the exact resolved digest of each Feature — a rebuild reuses that pinned version until the lock file is deliberately updated, the same role package-lock.json plays for npm dependencies.
A minimal, working example of exactly this setup is available at niksphere-devcontainer-singleapp-demo — clone it or open it directly in GitHub Codespaces to try it without setting anything up by hand.
3. Usage in VS Code (Including the Extension)
With Docker Desktop (or a compatible container runtime) and the Dev Containers extension installed, opening an Niksphere App project folder that contains a .devcontainer directory prompts VS Code to Reopen in Container. VS Code then:
- Builds the
appimage (base image plus the two Niksphere Features) and starts theengineanddbcontainers alongside it. - Installs the Niksphere VS Code Extension automatically — it is baked into the
appimage by thevscode-extensionFeature and registered via that Feature's owncustomizationsdeclaration, so no manual installation step is needed once the container is up. - Applies the Niksphere-specific editor settings shipped in
devcontainer.json(niksphere.cliPath, and an activeniksphere.environmentsentry pointing at the in-container Engine), so the Extension talks to the local Engine without any manual configuration.
From this point on, development matches the Local Native experience described in Developer Environment Topologies — Pascal syntax highlighting, the compile/publish build tasks (Ctrl+Shift+B / Ctrl+F5), the Environments and Apps sidebar views, and the Language Server — except the CLI, Engine, and database are entirely contained, versioned, and disposable rather than installed on the host.
WARNING
VS Code's own term for a single editor window with several unrelated folders open at once — typically saved as a *.code-workspace file — is a Multi-Root Workspace. Opening such a workspace file that happens to include an App's folder among several others is not equivalent to opening that App's folder directly: the Dev Containers extension does not reliably resolve which .devcontainer configuration applies out of an unrelated multi-root list, and may silently offer to create a new one instead of recognizing the existing one.
Recommendation: open the App's folder on its own (File > Open Folder…) when working inside its Dev Container, rather than a multi-root workspace file that also contains it.
4. Usage in GitHub Codespaces
Because devcontainer.json is a vendor-neutral, open specification, the exact same .devcontainer definition used locally runs unchanged inside a GitHub Codespace — no Codespaces-specific configuration is required. Creating a Codespace from an App repository builds the same app/engine/db stack on GitHub-operated infrastructure instead of the developer's own machine.
Two access modes follow directly from that:
- Local editor, cloud container — a local VS Code instance connects to the Codespace through the GitHub Codespaces extension, giving the same editor experience described in Section 3 while the containers themselves run remotely.
- Fully browser-based — the Codespace is opened directly in the Codespaces web client, with no local VS Code installation at all. This is the only Niksphere development topology with no local footprint beyond a web browser.
In both cases, port forwarding (including the loopback callback port nik env auth login opens for its OAuth flow) is handled automatically by Codespaces' own tunneling, the same way VS Code forwards it for a local container. GitHub Codespaces usage is billed under GitHub's own Codespaces pricing, independent of anything Niksphere-specific — see Developer Environment Topologies for how this compares cost- and isolation-wise to the other topologies.
WARNING
GitHub Codespaces only looks for devcontainer.json directly under a repository's root .devcontainer/ folder — either .devcontainer/devcontainer.json itself, or one level deeper as .devcontainer/<name>/devcontainer.json for repositories offering more than one configuration. It does not search arbitrarily nested subfolders elsewhere in the repository tree, so a configuration placed inside an individual App's own folder (e.g. MyApp/.devcontainer/devcontainer.json) is invisible to Codespaces, which silently falls back to a plain, tooling-less container.
For a repository holding several Niksphere Apps side by side (a monorepo), place every App's Dev Container configuration under the repository root's .devcontainer/, namespaced by App name:
<repository-root>/
├── .devcontainer/
│ ├── MyFirstApp/
│ │ ├── devcontainer.json
│ │ └── docker-compose.yml
│ └── MySecondApp/
│ ├── devcontainer.json
│ └── docker-compose.yml
├── MyFirstApp/
│ └── nikapp.yaml
└── MySecondApp/
└── nikapp.yamlVS Code resolves the same configuration correctly whether the developer opens the whole repository or the App's own subfolder directly. docker-compose.yml's workspace mount points at its own App folder two levels up (../../MyFirstApp) rather than at its own .devcontainer parent.
On the Codespaces side, the dropdown to choose between MyFirstApp and MySecondApp only appears via Code > Codespaces tab > "…" > New with options…, not the plain one-click Create codespace on <branch> button — that quick button always launches a single default configuration without ever prompting, regardless of how many are available. Using it on a repository with more than one configuration silently produces a plain, tooling-less container, the same failure mode as an undiscoverable configuration above.
A minimal, working example of this layout, with two independent Apps, is available at niksphere-devcontainer-multiapps-demo.
Related Documentation
- Developer Environment Topologies — Where the Dev Container fits among the other ways to combine the CLI, Engine, and Extension.
- Engine Deployment Concept — The official Engine Docker Container image used by the
engineservice. - Engine Database Concept — The PostgreSQL setup backing the
dbservice. - niksphere-devcontainer-singleapp-demo — Runnable single-App example.
- niksphere-devcontainer-multiapps-demo — Runnable example of two Apps sharing one repository.