Normalizes non-standard code-fence language tags across `docs/**` so a strict highlighter (Shiki, used by Fumadocs) won't fail the build on an unrecognized language, and unifies redundant synonym tags onto one canonical form per language. The current renderer (Speed-Highlight) detects the language from the code content, not the fence label, so this drift wasn't visible until now. ## Changes - `hcl` -> `tf` (199 fences, including indented ones nested in numbered/bulleted lists). Shiki ships `hcl` and `terraform` as two distinct grammars (not aliases); every `hcl`-tagged fence in `docs/**` is actually Terraform resource/data/provider syntax, so the more specific `terraform` grammar is correct for all of them. `tf` is Shiki's own alias for that grammar, and it's also what GitHub's own markdown renderer resolves to the same HCL/Terraform highlighting. - `pwsh`/`powershell` -> `ps1`. Both `ps` and `ps1` are registered PowerShell aliases in Shiki, but on GitHub's renderer only `.ps1` is a registered file extension (`.ps` isn't), so `ps1` renders identically to `powershell` there today while bare `ps` would silently lose highlighting. - `env` -> `dotenv` (a dedicated Shiki grammar for `KEY=VALUE` files) - `text`/`output`/`none`/`url` -> `txt`. Same built-in plain-text fallback either way, just shorter. - `Dockerfile` -> `dockerfile` (lowercase) - `bash`/`shell` -> `sh` (732 fences). Shiki and GitHub both alias all three to a single shell grammar; this was already the style guide's stated preference, just not enforced across the existing corpus until now. - `markdown` -> `md` (4 fences). Alias of the same grammar in both Shiki and GitHub. - `jsonc` -> `json` (1 fence). The block has no comments or trailing commas, so it doesn't need the comments-capable grammar. - `ts` -> `tsx` (2 fences, `docs/about/contributing/frontend.md`). Verified the actual content tokenizes identically under both grammars, and a sibling block in the same file already needs `tsx` for real JSX, so unifying to one tag is safe for this file. Documented a caveat: `tsx` mis-tokenizes the legacy angle-bracket type-assertion syntax (`<Type>value`), which is invalid in real `.tsx` files anyway, so use `value as Type` instead. - `yml` -> `yaml` (1 fence) - Updated `docs/.style/style-guide/formatting.md` to document all canonical tags `promql` (2 fences) and `caddyfile` (2 fences) are left as-is. Shiki doesn't bundle a grammar for either, so they need a custom grammar registration when the site adopts Shiki, rather than degrading to `txt`. Tracked as follow-up work under DOCS-118 and [DOCS-544](https://linear.app/codercom/issue/DOCS-544/vendor-a-local-promql-grammar-for-shiki-syntax-highlighting) (promql). Does not touch `offlinedocs/`. Linear: [DOCS-476](https://linear.app/codercom/issue/DOCS-476/normalize-docs-code-fence-languages-de-risk-shikifumadocs) <details> <summary>How the fence tags were verified</summary> Each tag was tested against a real `shiki@latest` highlighter instance (`codeToHtml`/`codeToTokens`) and cross-checked against GitHub's `@wooorm/starry-night` grammar sources (the renderer that actually displays these `.md` files today, in repo browsing and PR diffs), since that's what determines whether brevity is safe before Shiki adoption: ```text FAIL env -- Language `env` is not included in this bundle. FAIL Dockerfile -- Language `Dockerfile` is not included in this bundle. FAIL promql -- Language `promql` is not included in this bundle. FAIL caddyfile -- Language `caddyfile` is not included in this bundle. FAIL pwsh -- Language `pwsh` is not included in this bundle. FAIL output -- Language `output` is not included in this bundle. ``` `hcl` doesn't error in Shiki, since it's a real grammar, but that's exactly the trap: it was silently rendering every fence with the generic HCL grammar instead of the Terraform-specific one. Every `hcl`-tagged fence in `docs/**` was manually checked against `origin/main` and is genuinely Terraform content. For `ts`/`tsx`, tokenizing the actual doc content confirmed identical output under both grammars; a synthetic test with the legacy angle-bracket cast syntax confirmed `tsx` degrades on that specific construct, which the style guide now calls out. The first normalization pass only matched fence tags at column 0 (`^```tag$`), missing tags indented inside numbered/bulleted lists. A follow-up pass caught the remaining occurrences at any indentation level. </details> --- *This PR description and the underlying changes were prepared with Coder Agents assistance.*
14 KiB
Backend
This guide is designed to support both Coder engineers and community contributors in understanding our backend systems and getting started with development.
Coder’s backend powers the core infrastructure behind workspace provisioning, access control, and the overall developer experience. As the backbone of our platform, it plays a critical role in enabling reliable and scalable remote development environments.
The purpose of this guide is to help you:
- Understand how the various backend components fit together.
- Navigate the codebase with confidence and adhere to established best practices.
- Contribute meaningful changes - whether you're fixing bugs, implementing features, or reviewing code.
Need help or have questions? Join the conversation on our Discord server — we’re always happy to support contributors.
Platform Architecture
To understand how the backend fits into the broader system, we recommend reviewing the following resources:
-
General Concepts: Essential concepts and language used to describe how Coder is structured and operated.
-
Architecture: A high-level overview of the infrastructure layout, key services, and how components interact.
These sections provide the necessary context for navigating and contributing to the backend effectively.
Tech Stack
Coder's backend is built using a collection of robust, modern Go libraries and internal packages. Familiarity with these technologies will help you navigate the codebase and contribute effectively.
Core Libraries & Frameworks
- go-chi/chi: lightweight HTTP router for building RESTful APIs in Go
- golang-migrate/migrate: manages database schema migrations across environments
- coder/terraform-config-inspect (forked): used for parsing and analyzing Terraform configurations, forked to include PR #74
- coder/pq (forked): PostgreSQL driver forked to support rotating authentication tokens via
driver.Connector - coder/tailscale (forked): enables secure, peer-to-peer connectivity, forked to apply internal patches pending upstreaming
- coder/wireguard-go (forked): WireGuard networking implementation, forked to fix a data race and adopt the latest gVisor changes
- coder/ssh (forked): customized SSH server based on
gliderlabs/ssh, forked to include Tailscale-specific patches and avoid complex subpath dependencies - coder/bubbletea (forked): terminal UI framework for CLI apps, forked to remove an
init()function that interfered with web terminal output
Coder libraries
- coder/terraform-provider-coder: official Terraform provider for managing Coder resources via infrastructure-as-code
- coder/websocket: minimal WebSocket library for real-time communication
- coder/serpent: CLI framework built on
cobra, used for large, complex CLIs - coder/guts: generates TypeScript types from Go for shared type definitions
- coder/wgtunnel: WireGuard tunnel server for secure backend networking
Repository Structure
The Coder backend is organized into multiple packages and directories, each with a specific purpose. Here's a high-level overview of the most important ones:
- agent: core logic of a workspace agent, supports DevContainers, remote SSH, startup/shutdown script execution. Protobuf definitions for DRPC communication with
coderdare kept in proto. - cli: CLI interface for
codercommand built on coder/serpent. Input controls are defined in cliui, and testdata contains golden files for common CLI calls - cmd: entry points for CLI and services, including
coderd - coderd: the main API server implementation with chi endpoints
- audit: audit log logic, defines target resources, actions and extra fields
- autobuild: core logic of the workspace autobuild executor, periodically evaluates workspaces for next transition actions
- httpmw: HTTP middlewares mainly used to extract parameters from HTTP requests (e.g. current user, template, workspace, OAuth2 account, etc.) and storing them in the request context
- prebuilds: common interfaces for prebuild workspaces, feature implementation is in enterprise/prebuilds
- provisionerdserver: DRPC server for provisionerd instances, used to validate and extract Terraform data and resources, and store them in the database.
- rbac: RBAC engine for
coderd, including authz layer, role definitions and custom roles. Built on top of Open Policy Agent and Rego policies. - telemetry: records a snapshot with various workspace data for telemetry purposes. Once recorded the reporter sends it to the configured telemetry endpoint.
- tracing: extends telemetry with tracing data consistent with OpenTelemetry specification
- workspaceapps: core logic of a secure proxy to expose workspace apps deployed in a workspace
- wsbuilder: wrapper for business logic of creating a workspace build. It encapsulates all database operations required to insert a build record in a transaction.
- database: schema migrations, query logic, in-memory database, etc.
- db2sdk: translation between database structures and codersdk objects used by coderd API.
- dbauthz: AuthZ wrappers for database queries, ideally, every query should verify first if the accessor is eligible to see the query results.
- dbfake: helper functions to quickly prepare the initial database state for testing purposes (e.g. create N healthy workspaces and templates), operates on higher level than dbgen
- dbgen: helper functions to insert raw records to the database store, used for testing purposes
- dbmock: a store wrapper for database queries, useful to verify if the function has been called, used for testing purposes
- dbpurge: simple wrapper for periodic database cleanup operations
- migrations: an ordered list of up/down database migrations, use
./create_migration.sh my_migration_nameto modify the database schema - pubsub: PubSub implementation using PostgreSQL and in-memory drop-in replacement
- queries: contains SQL files with queries,
sqlccompiles them to Go functions - sqlc.yaml: defines mappings between SQL types and custom Go structures
- codersdk: user-facing API entities used by CLI and site to communicate with
coderdendpoints - dogfood: Terraform definition of the dogfood cluster deployment
- enterprise: enterprise-only features, notice similar file structure to repository root (
audit,cli,cmd,coderd, etc.) - provisioner: supported implementation of provisioners, Terraform and "echo" (for testing purposes)
- provisionerd: core logic of provisioner runner to interact provisionerd server, depending on a job acquired it calls template import, dry run or a workspace build
- pty: terminal emulation for agent shell
- support: compile a support bundle with diagnostics
- tailnet: core logic of Tailnet controller to maintain DERP maps, coordinate connections with agents and peers
- vpn: Coder Desktop (VPN) and tunneling components
Testing
The Coder backend includes a rich suite of unit and end-to-end tests. A variety of helper utilities are used throughout the codebase to make testing easier, more consistent, and closer to real behavior.
clitest
- Spawns an in-memory
serpent.Commandinstance for unit testing - Configures an authorized
codersdkclient - Once a
serpent.Invocationis created, tests can execute commands as if invoked by a real user
ptytest
ptytestattaches to aserpent.Invocationand simulates TTY input/outputptyprovides matchers and "write" operations for interacting with pseudo-terminals
coderdtest
- Provides shortcuts to spin up an in-memory
coderdinstance - Can start an embedded provisioner daemon
- Supports multi-user testing via
CreateFirstUserandCreateAnotherUser - Includes "busy wait" helpers like
AwaitTemplateVersionJobCompleted - oidctest can start a fake OIDC provider
testutil
- General-purpose testing utilities, including:
- chan.go: helpers for sending/receiving objects from channels (
TrySend,RequireReceive, etc.) - duration.go: set timeouts for test execution
- eventually.go: repeatedly poll for a condition using a ticker
- port.go: select a free random port
- prometheus.go: validate Prometheus metrics with expected values
- pty.go: read output from a terminal until a condition is met
- wait_buffer.go: thread-safe
io.Writerthat blocks until accumulated output contains a signal (WaitFor,WaitForNth,WaitForCond)
- chan.go: helpers for sending/receiving objects from channels (
dbtestutil
- Allows choosing between real and in-memory database backends for tests
WillUsePostgresis useful for skipping tests in CI environments that don't run Postgres
quartz
- Provides a mockable clock or ticker interface
- Allows manual time advancement
- Useful for testing time-sensitive or timeout-related logic
Quiz
Try to find answers to these questions before jumping into implementation work — having a solid understanding of how Coder works will save you time and help you contribute effectively.
- When you create a template, what does that do exactly?
- When you create a workspace, what exactly happens?
- How does the agent get the required information to run?
- How are provisioner jobs run?
Recipes
Adding database migrations and fixtures
Database migrations
Database migrations are managed with
migrate.
To add new migrations, use the following command:
./coderd/database/migrations/create_migration.sh my name
/home/coder/src/coder/coderd/database/migrations/000070_my_name.up.sql
/home/coder/src/coder/coderd/database/migrations/000070_my_name.down.sql
Then write queries into the generated .up.sql and .down.sql files and commit
them into the repository. The down script should make a best-effort to retain as
much data as possible.
Run make gen to generate models.
Database fixtures (for testing migrations)
There are two types of fixtures that are used to test that migrations don't break existing Coder deployments:
- Partial fixtures
migrations/testdata/fixtures - Full database dumps
migrations/testdata/full_dumps
Both types behave like database migrations (they also
migrate). Their behavior mirrors
Coder migrations such that when migration number 000022 is applied, fixture
000022 is applied afterwards.
Partial fixtures are used to conveniently add data to newly created tables so that we can ensure that this data is migrated without issue.
Full database dumps are for testing the migration of fully-fledged Coder deployments. These are usually done for a specific version of Coder and are often fixed in time. A full database dump may be necessary when testing the migration of multiple features or complex configurations.
To add a new partial fixture, run the following command:
./coderd/database/migrations/create_fixture.sh my fixture
/home/coder/src/coder/coderd/database/migrations/testdata/fixtures/000070_my_fixture.up.sql
Then add some queries to insert data and commit the file to the repo. See
000024_example.up.sql
for an example.
To create a full dump, run a fully fledged Coder deployment and use it to generate data in the database. Then shut down the deployment and take a snapshot of the database.
mkdir -p coderd/database/migrations/testdata/full_dumps/v0.12.2 && cd $_
pg_dump "postgres://coder@localhost:..." -a --inserts >000069_dump_v0.12.2.up.sql
Make sure sensitive data in the dump is desensitized, for instance names, emails, OAuth tokens and other secrets. Then commit the dump to the project.
To find out what the latest migration for a version of Coder is, use the following command:
git ls-files v0.12.2 -- coderd/database/migrations/*.up.sql
This helps in naming the dump (e.g. 000069 above).