Files
Nick Vigilante c84aa564ba docs: normalize code-fence languages for Shiki compatibility (#27161)
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.*
2026-07-15 14:07:09 -04:00

11 KiB

Configure a template for Dev Containers

This guide covers the Dev Containers Integration, which uses Docker. For environments without Docker, see Envbuilder as an alternative.

To enable Dev Containers in workspaces, configure your template with the Dev Containers modules and configurations outlined in this doc.

Dev Containers are currently not supported in Windows or macOS workspaces.

Configuration Modes

There are two approaches to configuring Dev Containers in Coder:

Manual Configuration

Use the coder_devcontainer Terraform resource to explicitly define which Dev Containers should be started in your workspace. This approach provides:

  • Predictable behavior and explicit control
  • Clear template configuration
  • Easier troubleshooting
  • Better for production environments

This is the recommended approach for most use cases.

Project Discovery

Alternatively, enable automatic discovery of Dev Containers in Git repositories. The agent scans for devcontainer.json files and surfaces them in the Coder UI. See Environment Variables for configuration options.

This approach is useful when developers frequently switch between repositories or work with many projects, as it reduces template maintenance overhead.

Install the Dev Containers CLI

Use the devcontainers-cli module to ensure the @devcontainers/cli is installed in your workspace:

module "devcontainers-cli" {
  count    = data.coder_workspace.me.start_count
  source   = "registry.coder.com/coder/devcontainers-cli/coder"
  agent_id = coder_agent.dev.id
}

Alternatively, install the devcontainer CLI manually in your base image.

Configure Automatic Dev Container Startup

The coder_devcontainer resource automatically starts a Dev Container in your workspace, ensuring it's ready when you access the workspace:

resource "coder_devcontainer" "my-repository" {
  count            = data.coder_workspace.me.start_count
  agent_id         = coder_agent.dev.id
  workspace_folder = "/home/coder/my-repository"
}

The workspace_folder attribute must point to a valid project folder containing a devcontainer.json file. Consider using the git-clone module to ensure your repository is cloned and ready for automatic startup.

For multi-repo workspaces, define multiple coder_devcontainer resources, each pointing to a different repository. Each one runs as a separate sub-agent with its own terminal and apps in the dashboard.

Enable Dev Containers Integration

Dev Containers integration is enabled by default in Coder 2.24.0 and later. You don't need to set any environment variables unless you want to change the default behavior.

If you need to explicitly disable Dev Containers, set the CODER_AGENT_DEVCONTAINERS_ENABLE environment variable to false:

resource "docker_container" "workspace" {
  count = data.coder_workspace.me.start_count
  image = "codercom/oss-dogfood:latest"
  env = [
    "CODER_AGENT_DEVCONTAINERS_ENABLE=false",  # Explicitly disable
    # ... Other environment variables.
  ]
  # ... Other container configuration.
}

See the Environment Variables section below for more details on available configuration options.

Environment Variables

The following environment variables control Dev Container behavior in your workspace. Both CODER_AGENT_DEVCONTAINERS_ENABLE and CODER_AGENT_DEVCONTAINERS_PROJECT_DISCOVERY_ENABLE are enabled by default, so you typically don't need to set them unless you want to explicitly disable the feature.

CODER_AGENT_DEVCONTAINERS_ENABLE

Default: trueAdded in: v2.24.0

Enables the Dev Containers integration in the Coder agent.

The Dev Containers feature is enabled by default. You can explicitly disable it by setting this to false.

CODER_AGENT_DEVCONTAINERS_PROJECT_DISCOVERY_ENABLE

Default: trueAdded in: v2.25.0

Enables automatic discovery of Dev Containers in Git repositories.

When enabled, the agent scans the configured working directory (set via the directory attribute in coder_agent, typically the user's home directory) for Git repositories. If the directory itself is a Git repository, it searches that project. Otherwise, it searches immediate subdirectories for Git repositories.

For each repository found, the agent looks for devcontainer.json files in the standard locations and surfaces discovered Dev Containers in the Coder UI. Discovery respects .gitignore patterns.

Set to false if you prefer explicit configuration via coder_devcontainer.

CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE

Default: falseAdded in: v2.25.0

Automatically starts Dev Containers discovered via project discovery.

When enabled, discovered Dev Containers will be automatically built and started during workspace initialization. This only applies to Dev Containers found via project discovery. Dev Containers defined with the coder_devcontainer resource always auto-start regardless of this setting.

Attach Resources to Dev Containers

You can attach coder_app, coder_script, and coder_env resources to a coder_devcontainer by referencing its subagent_id attribute as the agent_id:

resource "coder_devcontainer" "my-repository" {
  count            = data.coder_workspace.me.start_count
  agent_id         = coder_agent.dev.id
  workspace_folder = "/home/coder/my-repository"
}

resource "coder_app" "code-server" {
  count        = data.coder_workspace.me.start_count
  agent_id     = coder_devcontainer.my-repository[0].subagent_id
  # ...
}

resource "coder_script" "dev-setup" {
  count        = data.coder_workspace.me.start_count
  agent_id     = coder_devcontainer.my-repository[0].subagent_id
  # ...
}

resource "coder_env" "my-var" {
  count    = data.coder_workspace.me.start_count
  agent_id = coder_devcontainer.my-repository[0].subagent_id
  # ...
}

This also enables using Coder registry modules that depend on these resources inside dev containers, by passing the subagent_id as the module's agent_id.

Terraform-managed dev containers

When a coder_devcontainer has any coder_app, coder_script, or coder_env resource attached, it becomes a terraform-managed dev container. This changes how Coder handles the sub-agent:

  • The sub-agent is pre-defined during Terraform provisioning rather than created dynamically.
  • On dev container configuration changes, Coder updates the sub-agent in-place instead of deleting and recreating it.

Interaction with devcontainer.json customizations

Terraform-defined resources and devcontainer.json customizations work together with some limitations. The displayApps settings from devcontainer.json are applied to terraform-managed dev containers, so you can control built-in app visibility (e.g., hide VS Code Insiders) via devcontainer.json even when using Terraform resources.

However, custom apps defined in devcontainer.json are not applied to terraform-managed dev containers. If you need custom apps, define them as coder_app resources in Terraform instead.

Per-Container Customizations

Developers can customize individual dev containers using the customizations.coder block in their devcontainer.json file. Available options include:

  • ignore — Hide a dev container from Coder completely
  • autoStart — Control whether the container starts automatically (requires CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE to be enabled)
  • name — Set a custom agent name
  • displayApps — Control which built-in apps appear
  • apps — Define custom applications

For the full reference, see Customizing dev containers.

Complete Template Example

Here's a simplified template example that uses Dev Containers with manual configuration:

terraform {
  required_providers {
    coder  = { source = "coder/coder" }
    docker = { source = "kreuzwerker/docker" }
  }
}

provider "coder" {}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}

resource "coder_agent" "dev" {
  arch                    = "amd64"
  os                      = "linux"
  startup_script_behavior = "blocking"
  startup_script          = "sudo service docker start"
  shutdown_script         = "sudo service docker stop"
  # ...
}

module "devcontainers-cli" {
  count    = data.coder_workspace.me.start_count
  source   = "registry.coder.com/coder/devcontainers-cli/coder"
  agent_id = coder_agent.dev.id
}

resource "coder_devcontainer" "my-repository" {
  count            = data.coder_workspace.me.start_count
  agent_id         = coder_agent.dev.id
  workspace_folder = "/home/coder/my-repository"
}

# Attaching resources to dev containers is optional. By attaching
# this resource to the dev container, we are changing how the dev
# container will be treated by Coder. This limits the ability to
# customize the injected agent via the devcontainer.json file.
resource "coder_env" "env" {
  count    = data.coder_workspace.me.start_count
  agent_id = coder_devcontainer.my-repository[0].subagent_id
  name     = "MY_VAR"
  value    = "my-value"
}

Alternative: Project Discovery with Autostart

By default, discovered containers appear in the dashboard but developers must manually start them. To have them start automatically, enable autostart:

resource "docker_container" "workspace" {
  count = data.coder_workspace.me.start_count
  image = "codercom/oss-dogfood:latest"
  env = [
    # Project discovery is enabled by default, but autostart is not.
    # Enable autostart to automatically build and start discovered containers:
    "CODER_AGENT_DEVCONTAINERS_DISCOVERY_AUTOSTART_ENABLE=true",
    # ... Other environment variables.
  ]
  # ... Other container configuration.
}

With autostart enabled:

  • Discovered containers automatically build and start during workspace initialization
  • The coder_devcontainer resource is not required
  • Developers can work with multiple projects seamlessly

Note

When using project discovery, you still need to install the devcontainers CLI using the module or in your base image.

Example Template

The Docker (Dev Containers) starter template demonstrates Dev Containers integration using Docker-in-Docker. It includes the devcontainers-cli module, git-clone module, and the coder_devcontainer resource.

Next Steps