DEV Community

John  Ajera
John Ajera

Posted on

Creating Your Own Dev Container Feature for VS Code

Creating Your Own Dev Container Feature for VS Code

This article demonstrates how to create and publish your own Dev Container Feature for VS Code. We'll use the Amazon Q CLI feature from the jajera/features repository as a practical example, showing the complete process from forking the starter repository to getting your feature listed on containers.dev.


High-Level Steps

Creating and publishing a Dev Container Feature involves:

  1. Fork the Feature Starter Repository - Start with the official template
  2. Create Your Feature Structure - Define metadata and installation script
  3. Test Locally - Verify your feature works before publishing
  4. Publish to GitHub Container Registry - Make your feature available via GHCR
  5. Submit to containers.dev Index - Add your feature to the official collection

Prerequisites

  • Git and GitHub account
  • VS Code with Remote - Containers extension
  • Basic shell scripting knowledge
  • GitHub Personal Access Token (for publishing to GHCR)

Use Case: Amazon Q CLI Feature

When working with Amazon Q CLI, manually installing it in every Dev Container became repetitive. The solution was to create a reusable Dev Container Feature that automatically installs Amazon Q CLI whenever a container is built. This feature is now available at ghcr.io/jajera/features/amazon-q-cli:1 and can be used by anyone in their development containers.


Step-by-Step Implementation

Step 1: Fork and Clone the Starter Repository

Start by forking the devcontainers/feature-starter repository:

  1. Navigate to the Feature Starter repository
  2. Click the Fork button to create a copy in your GitHub account
  3. Clone your forked repository locally:
git clone https://github.com/your-username/feature-starter.git
cd feature-starter
Enter fullscreen mode Exit fullscreen mode

Repository structure:

feature-starter/
├── src/
│   └── [your-feature-name]/
│       ├── devcontainer-feature.json
│       ├── install.sh
│       └── README.md
├── test/
│   └── [your-feature-name]/
│       └── test.sh
└── .github/
    └── workflows/
        └── release.yml
Enter fullscreen mode Exit fullscreen mode

Key points:

  • src/ contains all your features
  • Each feature has its own subdirectory
  • test/ contains test scripts for each feature
  • GitHub Actions workflow handles publishing

Step 2: Create Feature Directory Structure

Create a new directory for your feature in the src/ folder:

mkdir -p src/amazon-q-cli
Enter fullscreen mode Exit fullscreen mode

Required files:

  • devcontainer-feature.json - Feature metadata (required)
  • install.sh - Installation script (required)
  • README.md - Documentation (recommended)

Step 3: Define Feature Metadata

Create devcontainer-feature.json in your feature directory:

{
  "id": "amazon-q-cli",
  "version": "1.0.0",
  "name": "Amazon Q CLI",
  "documentationURL": "https://github.com/jajera/features/tree/main/src/amazon-q-cli",
  "description": "Installs the Amazon Q Command Line Interface for AWS development.",
  "options": {},
  "installsAfter": []
}
Enter fullscreen mode Exit fullscreen mode

Configuration fields:

  • id: Unique identifier for your feature (lowercase, hyphens)
  • version: Semantic version (e.g., "1.0.0")
  • name: Human-readable display name
  • documentationURL: Link to your feature's documentation
  • description: Brief description of what the feature does
  • options: Configurable parameters (empty object if none)
  • installsAfter: Array of feature IDs that must install first

Key points:

  • Use semantic versioning for releases
  • Keep IDs lowercase with hyphens (no underscores)
  • Provide clear, concise descriptions
  • Link to comprehensive documentation

Step 4: Create Installation Script

Create install.sh with executable permissions:

#!/bin/bash
set -e

# Install Amazon Q CLI
curl -fsSL https://amazon-q-cli.s3.amazonaws.com/install.sh | bash

# Verify installation
if ! command -v q &> /dev/null; then
    echo "Error: Amazon Q CLI installation failed"
    exit 1
fi

echo "Amazon Q CLI installed successfully"
Enter fullscreen mode Exit fullscreen mode

Best practices:

  • Always use set -e to exit on errors
  • Use curl -fsSL for secure downloads
  • Verify installation succeeded
  • Provide helpful error messages
  • Handle both root and non-root users when needed

Make the script executable:

chmod +x src/amazon-q-cli/install.sh
Enter fullscreen mode Exit fullscreen mode

Step 5: Test Your Feature Locally

Create a test devcontainer.json to verify your feature works:

{
  "name": "Test Amazon Q CLI Feature",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "./src/amazon-q-cli": {}
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing steps:

  1. Open the repository in VS Code
  2. Press Ctrl+Shift+P (or Cmd+Shift+P on Mac)
  3. Select "Reopen in Container"
  4. Wait for the container to build
  5. Open a terminal and verify installation:
q --version
Enter fullscreen mode Exit fullscreen mode

What to verify:

  • Feature installs without errors
  • Tool is accessible in PATH
  • Tool functions correctly
  • No permission issues

Step 6: Publish to GitHub Container Registry

The forked repository already includes a release workflow (.github/workflows/release.yml) that automatically publishes your features to GitHub Container Registry (GHCR) when you push changes to the main branch.

Update the test workflow:

Before publishing, ensure your feature is included in the test workflow. Edit .github/workflows/test.yaml and add your feature name to the matrix lists:

strategy:
  matrix:
    features:
      - ag
      - amazon-q-cli
      - aws-sam-cli
      - gcloud-cli
      - zip
      - your-feature-name  # Add your feature here
Enter fullscreen mode Exit fullscreen mode

Important: Add your feature name to both matrix lists in the test workflow:

  • In the test-autogenerated job matrix
  • In the test-scenarios job matrix

This ensures your feature is tested against multiple base images and scenarios before publishing.

Publishing process:

  1. Push your changes to the main branch
  2. GitHub Actions automatically builds and publishes (the devcontainers/action handles container operations)
  3. Feature becomes available at ghcr.io/your-username/features/feature-name:version

Reference format:

ghcr.io/jajera/features/amazon-q-cli:1
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Features are published to GHCR automatically on push
  • Version tags are created automatically
  • Use :1 for major version 1, :2 for major version 2, etc.
  • Each feature gets its own container image

Step 7: Add to containers.dev Index

To make your feature discoverable on containers.dev/features, add it to the official index.

Step 7.1: Fork the Repository

Fork the devcontainers/devcontainers.github.io repository.

Step 7.2: Edit collection-index.yml

Navigate to _data/collection-index.yml and add your feature entry:

- name: Amazon Q CLI
  maintainer: Your Name
  reference: ghcr.io/jajera/features/amazon-q-cli:1
  latest_version: 1.0.0
Enter fullscreen mode Exit fullscreen mode

Entry format:

  • name: Display name (matches your feature name)
  • maintainer: Your name or GitHub username
  • reference: Full GHCR reference with version tag
  • latest_version: Current version number

Example PR: See PR #568 for a complete example of adding a feature to the collection index.

Step 7.3: Create Pull Request

  1. Commit your changes:
git add _data/collection-index.yml
git commit -m "Add Amazon Q CLI feature to collection"
git push origin gh-pages
Enter fullscreen mode Exit fullscreen mode
  1. Create a Pull Request on the original repository with a clear description
  2. Complete the PR checklist - Ensure you've fulfilled all requirements:
  • [ ] Feature is published to GitHub Container Registry (GHCR)
  • [ ] Feature has been tested and works correctly
  • [ ] Feature has proper documentation (README.md)
  • [ ] Entry follows the correct format in collection-index.yml
  • [ ] Feature name, maintainer, and reference are accurate
  • [ ] Latest version matches the published version in GHCR
  • [ ] PR description explains what the feature does
  1. Wait for review - maintainers will verify your feature
  2. Once merged, your feature appears on containers.dev

Review process:

  • Maintainers verify the feature works
  • Check that documentation is complete
  • Ensure the feature follows best practices
  • May request changes or improvements

Step 7.4: Adding Additional Features (No Re-registration Needed)

Important: Once your repository is successfully registered with the first feature, you can add more features to the same repository without submitting additional PRs.

How it works:

  • A scheduled automated job periodically scans registered repositories and discovers all features in the src/ directory
  • New features are automatically added to the containers.dev/features index during the next scheduled run
  • Your features will appear when searching for your maintainer name (e.g., containers.dev/features?search=jajera) after the indexing job completes

Note: The indexing job runs on a schedule, so there may be a delay before your new features appear in the index. This is not real-time, but typically happens within a reasonable timeframe.

What you need to do:

  1. Add your new feature to the src/ directory in your repository
  2. Update the test workflow (.github/workflows/test.yaml) to include your new feature in the matrix lists
  3. Push your changes - the release workflow will publish the feature to GHCR
  4. Wait for automatic discovery - the indexing job will detect and add your new feature

Example: The jajera/features repository has multiple features (ag, amazon-q-cli, aws-sam-cli, gcloud-cli, zip) that were all automatically discovered after the initial registration. You can see them all listed at containers.dev/features?search=jajera.

Note: Only the first feature requires a manual PR to register your repository. All subsequent features in the same repository are automatically indexed.


Complete Example: Amazon Q CLI Feature

Here's the complete implementation of the Amazon Q CLI feature:

devcontainer-feature.json

{
  "id": "amazon-q-cli",
  "version": "1.0.0",
  "name": "Amazon Q CLI",
  "documentationURL": "https://github.com/jajera/features/tree/main/src/amazon-q-cli",
  "description": "Installs the Amazon Q Command Line Interface for AWS development.",
  "options": {},
  "installsAfter": []
}
Enter fullscreen mode Exit fullscreen mode

install.sh

#!/bin/bash
set -e

# Install Amazon Q CLI
curl -fsSL https://amazon-q-cli.s3.amazonaws.com/install.sh | bash

# Verify installation
if ! command -v q &> /dev/null; then
    echo "Error: Amazon Q CLI installation failed"
    exit 1
fi

echo "Amazon Q CLI installed successfully"
Enter fullscreen mode Exit fullscreen mode

Usage in devcontainer.json

{
  "name": "My Dev Container",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "ghcr.io/jajera/features/amazon-q-cli:1": {}
  }
}
Enter fullscreen mode Exit fullscreen mode

Implementation details:

  • Simple installation via official AWS install script
  • Automatic PATH configuration handled by install script
  • Works on Ubuntu-based containers
  • No additional configuration required

Feature Structure Summary

After creating your feature, you'll have:

File Required Purpose
devcontainer-feature.json Yes Feature metadata and configuration
install.sh Yes Installation script
README.md No Documentation (highly recommended)
test/test.sh No Test script (recommended)

Directory structure:

src/
└── amazon-q-cli/
    ├── devcontainer-feature.json
    ├── install.sh
    └── README.md
Enter fullscreen mode Exit fullscreen mode

Important Notes

Versioning Conventions

  • Semantic versioning: Use MAJOR.MINOR.PATCH (e.g., 1.0.0)
  • GHCR tags: Use :1, :2 for major versions
  • Breaking changes: Increment major version
  • New features: Increment minor version
  • Bug fixes: Increment patch version

Naming Conventions

  • Feature IDs: Lowercase with hyphens (amazon-q-cli, not AmazonQCLI)
  • Directory names: Match feature ID exactly
  • Display names: Use proper capitalization (Amazon Q CLI)

Testing Best Practices

  • Test on multiple base images (Ubuntu, Debian, etc.)
  • Verify installation works for both root and non-root users
  • Test with different architectures if applicable
  • Include test scripts in test/ directory

Documentation Requirements

  • Clear description of what the feature does
  • Installation requirements or prerequisites
  • Usage examples
  • Configuration options (if any)
  • Troubleshooting tips

Troubleshooting

Build Errors

Issue: Feature fails to build

  • Check that install.sh has executable permissions
  • Verify all commands in install.sh are correct
  • Ensure devcontainer-feature.json is valid JSON
  • Check GitHub Actions logs for specific errors

Solution:

# Verify script permissions
ls -la src/amazon-q-cli/install.sh

# Test JSON syntax
cat src/amazon-q-cli/devcontainer-feature.json | jq .
Enter fullscreen mode Exit fullscreen mode

GHCR Publishing Issues

Issue: Feature not appearing in GHCR

  • Verify GitHub Actions workflow is configured correctly
  • Check that GITHUB_TOKEN has package write permissions
  • Ensure workflow triggers on the correct branch
  • Review GitHub Actions logs for errors

Solution:

  • Check repository Settings → Actions → General
  • Verify "Workflow permissions" allows read/write
  • Ensure workflow file is in .github/workflows/

PR Rejection Reasons

Common reasons for PR rejection:

  1. Missing documentation - Add comprehensive README
  2. Feature doesn't work - Test thoroughly before submitting
  3. Incorrect format - Follow collection-index.yml format exactly
  4. Duplicate feature - Check if similar feature already exists
  5. Security concerns - Ensure install script is secure

Prevention:

  • Test your feature extensively
  • Follow all formatting requirements
  • Provide complete documentation
  • Review existing features for examples

Testing Problems

Issue: Feature works locally but fails in container

  • Check PATH configuration
  • Verify user permissions
  • Ensure dependencies are installed
  • Test with the same base image

Solution:

  • Create a test devcontainer.json with your feature
  • Reopen in container in VS Code
  • Run install.sh manually to debug

Sharing Your Tools with the Community

Creating Dev Container Features isn't just about solving your own problems—it's a powerful way to share your tools and solutions with the entire developer community.

Why Share Your Features?

Help other developers save time:

  • Developers can use your feature instead of writing their own installation scripts
  • Reduces setup friction for common tools
  • Enables faster onboarding for new team members

Standardize tool installation:

  • Consistent installation across different projects
  • Version control for tool versions
  • Reproducible development environments

Build your reputation:

  • Showcase your expertise in tooling and DevOps
  • Contribute to open source ecosystem
  • Get recognition from the community

Contribute to the Dev Container ecosystem:

  • Expand the available feature library
  • Help make Dev Containers more powerful
  • Support the growth of containerized development

Community Impact

When you publish a feature to containers.dev, it becomes:

  • Discoverable - Developers can find it through search
  • Reusable - Anyone can use it in their devcontainer.json
  • Maintainable - You control updates and improvements
  • Documented - Your README helps others understand usage

Examples of Community-Shared Features

The containers.dev/features index contains hundreds of community-contributed features, including:

  • Development tools (CLIs, SDKs, frameworks)
  • Database clients and utilities
  • Cloud provider tools (AWS, Azure, GCP)
  • Language runtimes and package managers
  • Code quality and testing tools

Making Development Environments More Accessible

By sharing your features, you're making development environments more accessible to everyone:

  • New developers can get started faster
  • Teams can standardize their tooling
  • Open source projects can provide better contributor experiences
  • The community benefits from collective knowledge

Call to Action

If you've created a useful tool installation script or solved a common setup problem, consider packaging it as a Dev Container Feature:

  1. Identify a need - What tool do you install repeatedly?
  2. Create the feature - Follow the steps in this article
  3. Test thoroughly - Ensure it works reliably
  4. Share with the community - Submit to containers.dev

Your contribution could save hundreds of developers time and make their development workflows smoother. The Dev Container ecosystem grows stronger with each shared feature.


Verification

After publishing your feature, verify it's working:

# Test in a devcontainer.json
# Create a test project with:
# {
#   "features": {
#     "ghcr.io/jajera/features/amazon-q-cli:1": {}
#   }
# }

# Verify tool is installed
q --version
Enter fullscreen mode Exit fullscreen mode

Check your feature on containers.dev:

  1. Visit containers.dev/features
  2. Search for your feature name
  3. Verify it appears in search results
  4. Check that documentation links work

Conclusion

Creating and sharing Dev Container Features is a rewarding way to improve development workflows for yourself and the community. By following this guide, you can:

  • Package your tools as reusable features
  • Publish them to GitHub Container Registry
  • Make them discoverable on containers.dev
  • Contribute to the open source ecosystem

Start with a simple feature, test it thoroughly, and share it with the community. Your contribution will help make development environments more accessible and standardized for everyone.

Top comments (0)