Skip to content

Using as a template

This guide explains how to use nix-config as a starting point for your TypeScript monorepo projects.

  1. Click “Use this template” button on GitHub
  2. Create your new repository
  3. Clone to your local machine
  4. Follow customization steps below
Terminal window
nix flake init --template github:sciexp/nix-config
Terminal window
git clone https://github.com/cameronraysmith/infra.git my-project
cd my-project
rm -rf .git
git init
git add .
git commit -m "chore: initial commit from infra template"

This template uses framework-agnostic, purpose-based naming that works for both the template itself and your forked projects.

Template package: @infra/docs

Why this naming works:

  1. Framework independence: No mention of Astro/Starlight - these are implementation details
  2. Template perspective: Most projects need documentation - immediately useful
  3. Brevity: Shortest meaningful name
  4. Pattern clarity: @{scope}/{purpose} scales to multiple packages
  5. Template duality: Works as both a working deployment and a forkable template

When you fork this template, you’ll rename packages to match your organization and project:

Single-package projects:

@myorg/docs # If docs are your main/only package
@myorg/api # If building an API service
@myorg/web # If building a web application

Multi-package projects:

@mycompany/docs # Documentation site
@mycompany/api # API backend
@mycompany/web # Web frontend
@mycompany/shared # Shared utilities

Pattern: Use the package’s purpose, not its implementation framework.

Understanding how to structure your deployment URLs is important for scalability.

Reserve these for organization-wide services:

example.com # Main org site
www.example.com # Main org site
docs.example.com # Org-wide documentation
api.example.com # Org-wide API gateway
blog.example.com # Org blog

Use project subdomains for individual applications:

{project}.example.com # Project main site
{component}.{project}.example.com # Project components

If your project has only one public-facing site:

Configuration:

  • Package: @myorg/docs
  • Worker: myproject
  • Route: myproject.example.com

When to use:

  • Documentation sites
  • Simple web applications
  • Single-purpose services

If your project has multiple public-facing components:

Configuration:

  • Package: @myorg/docs → Worker: myproject-docsdocs.myproject.example.com
  • Package: @myorg/api → Worker: myproject-apiapi.myproject.example.com
  • Package: @myorg/web → Worker: myproject-webwww.myproject.example.com

When to use:

  • Multi-component architectures
  • Clear separation of concerns needed
  • Professional multi-service setup

For infra:

  • Package: @infra/docs
  • Worker: nix-config-docs
  • Route: infra.cameronraysmith.net

Rationale:

  • Preserves docs.* for actual org documentation
  • ts-nix is short identifier for the template project
  • Shows project-level subdomain pattern

When forking this template, update these files:

{
"name": "my-project",
"description": "Your project description",
"repository": {
"type": "git",
"url": "https://github.com/yourorg/my-project.git"
},
"workspaces": ["packages/*"]
}

Rename packages/docs/ to match your package purpose:

Terminal window
mv packages/docs packages/my-package-name

Update packages/my-package-name/package.json:

{
"name": "@yourorg/my-package-name",
"description": "Your package description",
"repository": {
"type": "git",
"url": "https://github.com/yourorg/my-project.git"
},
"release": {
"plugins": [
// ... existing plugins ...
[
"semantic-release-major-tag",
{
"customTags": [
"my-package-name-v${major}",
"my-package-name-v${major}.${minor}"
]
}
]
]
}
}

Update packages/my-package-name/wrangler.jsonc:

{
"name": "my-project-package-name",
"routes": [
{
"pattern": "my-project.example.com",
"custom_domain": true
}
]
}

Update workflow matrices in .github/workflows/:

ci.yaml:

matrix:
package:
- name: my-package-name
path: packages/my-package-name

release.yaml:

matrix:
package:
- name: my-package-name
path: packages/my-package-name

Update filter patterns:

# Before
bun run --filter '@infra/docs' dev
# After
bun run --filter '@yourorg/my-package-name' dev

Search and replace @infra/docs with your package name.

Update:

  • README.md - Project name and description
  • CONTRIBUTING.md - Scope examples in commit message section
  • packages/my-package-name/README.md - Package-specific docs

Update flake.nix:

{
description = "my-project: Your project description";
# ... rest of flake
}

After customization:

Terminal window
nix develop
bun install
Terminal window
# Build
just build
# Run tests
just test
# Run in development
just dev
Terminal window
nix flake check --impure
Terminal window
# Dry run to verify configuration
just test-release

If using SOPS for secrets management:

Terminal window
# Generate new age keys
just sops-bootstrap dev
just sops-bootstrap ci
# Add secrets
just edit-secrets
# Upload to GitHub
just sops-upload-github-key
just sops-setup-github

See Secrets management guide for details.

As your project grows, add additional packages:

Terminal window
mkdir -p packages/new-package/src
cd packages/new-package
{
"name": "@yourorg/new-package",
"version": "0.0.0-development",
"private": true,
"description": "Package description",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/yourorg/my-project.git"
},
"license": "MIT",
"scripts": {
"build": "...",
"test": "...",
"test-release": "semantic-release --dry-run --no-ci"
},
"release": {
"extends": "semantic-release-monorepo",
"branches": [{ "name": "main" }],
"npmPublish": false,
"plugins": [
// Copy from existing package
]
}
}

Add to .github/workflows/ci.yaml and .github/workflows/release.yaml:

matrix:
package:
- name: existing-package
path: packages/existing-package
- name: new-package
path: packages/new-package
  • tsconfig.json extending root config
  • Test configuration if needed
  • Build configuration
Terminal window
cd ../..
bun install
just test-pkg new-package

After forking, you may want to remove template-specific documentation:

  • docs/notes/ - Template development notes (safe to remove)
  • Template-specific guides (if creating your own)
  • Example content in packages/docs/src/content/docs/
  • CONTRIBUTING.md - Conventional commit guidelines
  • .github/workflows/ - CI/CD automation
  • justfile - Task automation (customize commands)
  • Nix configuration - Development environment

When ready for public releases:

Ensure your team understands and uses conventional commit format.

Terminal window
# Test at root
bun run test-release
# Test per package
cd packages/my-package
bun run test-release

Uncomment triggers in .github/workflows/release.yaml:

# Change from:
on:
workflow_dispatch:
inputs:
dry-run:
default: true
# To:
on:
push:
branches:
- main
workflow_dispatch:
inputs:
dry-run:
default: false

Push a conventional commit and watch the release workflow:

Terminal window
git commit -m "feat(my-package): add initial functionality"
git push
gh run watch

See Architecture decisions for release strategy details.

If you encounter issues with the template itself:

For your forked project:

After customization:

  1. Set up CI/CD - Follow CI/CD setup guide
  2. Configure secrets - Follow Secrets management guide
  3. Add tests - Follow Testing guide
  4. Deploy - Configure Cloudflare Workers or your deployment target
  5. Start building - Create your application code

Welcome to your new TypeScript monorepo!