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:
- Fork the Feature Starter Repository - Start with the official template
- Create Your Feature Structure - Define metadata and installation script
- Test Locally - Verify your feature works before publishing
- Publish to GitHub Container Registry - Make your feature available via GHCR
- 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:
- Navigate to the Feature Starter repository
- Click the Fork button to create a copy in your GitHub account
- Clone your forked repository locally:
git clone https://github.com/your-username/feature-starter.git
cd feature-starter
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
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
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": []
}
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"
Best practices:
- Always use
set -eto exit on errors - Use
curl -fsSLfor 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
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": {}
}
}
Testing steps:
- Open the repository in VS Code
- Press
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - Select "Reopen in Container"
- Wait for the container to build
- Open a terminal and verify installation:
q --version
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
Important: Add your feature name to both matrix lists in the test workflow:
- In the
test-autogeneratedjob matrix - In the
test-scenariosjob matrix
This ensures your feature is tested against multiple base images and scenarios before publishing.
Publishing process:
- Push your changes to the main branch
-
GitHub Actions automatically builds and publishes (the
devcontainers/actionhandles container operations) -
Feature becomes available at
ghcr.io/your-username/features/feature-name:version
Reference format:
ghcr.io/jajera/features/amazon-q-cli:1
Key points:
- Features are published to GHCR automatically on push
- Version tags are created automatically
- Use
:1for major version 1,:2for 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
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
- Commit your changes:
git add _data/collection-index.yml
git commit -m "Add Amazon Q CLI feature to collection"
git push origin gh-pages
- Create a Pull Request on the original repository with a clear description
- 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
- Wait for review - maintainers will verify your feature
- 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:
-
Add your new feature to the
src/directory in your repository -
Update the test workflow (
.github/workflows/test.yaml) to include your new feature in the matrix lists - Push your changes - the release workflow will publish the feature to GHCR
- 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": []
}
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"
Usage in devcontainer.json
{
"name": "My Dev Container",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/jajera/features/amazon-q-cli:1": {}
}
}
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
Important Notes
Versioning Conventions
-
Semantic versioning: Use
MAJOR.MINOR.PATCH(e.g.,1.0.0) -
GHCR tags: Use
:1,:2for 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, notAmazonQCLI) - 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.shhas executable permissions - Verify all commands in
install.share correct - Ensure
devcontainer-feature.jsonis 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 .
GHCR Publishing Issues
Issue: Feature not appearing in GHCR
- Verify GitHub Actions workflow is configured correctly
- Check that
GITHUB_TOKENhas 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:
- Missing documentation - Add comprehensive README
- Feature doesn't work - Test thoroughly before submitting
- Incorrect format - Follow collection-index.yml format exactly
- Duplicate feature - Check if similar feature already exists
- 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:
- Identify a need - What tool do you install repeatedly?
- Create the feature - Follow the steps in this article
- Test thoroughly - Ensure it works reliably
- 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
Check your feature on containers.dev:
- Visit containers.dev/features
- Search for your feature name
- Verify it appears in search results
- 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)