npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dockyard-cli

v0.1.0

Published

Platform-agnostic infrastructure as code for PaaS. Manage Dokploy, Railway, and other platforms from a config file.

Readme

Dockyard

Dockyard is a CLI tool that manages PaaS infrastructure from a config file. You define your projects, applications, databases, and domains in dac.config.ts, and the tool creates, updates, or deletes resources on your provider to match. It currently supports Dokploy and Railway. The provider interface is generic, so other platforms can be added.

Your project can be written in any language. The dac.config.ts file is just a config that sits in your repo.

Install

Requires Bun.

bun add -g dockyard-cli

That's it. You now have the dac command available everywhere.

If you don't want a global install, you can use bunx to run it without installing:

bunx dockyard-cli init
bunx dockyard-cli plan
bunx dockyard-cli apply

Or build from source:

git clone https://github.com/Nu11ified/Dockyard.git
cd Dockyard && bun install && bun run build
cp dist/dac ~/.local/bin/

Quick start

1. Create a config file in your project:

dac init

This creates dac.config.ts in the current directory. It works in any project: Go, Python, Rust, a static site, anything.

2. Set your provider credentials:

Dokploy:

export DOKPLOY_URL="https://your-dokploy-instance.com"
export DOKPLOY_API_KEY="your-api-key"

Get your API key from the Dokploy dashboard under Settings > API.

Railway:

export RAILWAY_TOKEN="your-railway-api-token"

Get your token from the Railway dashboard.

3. Edit dac.config.ts:

export default {
  providers: {
    dokploy: {
      type: "dokploy",
      url: process.env.DOKPLOY_URL!,
      apiKey: process.env.DOKPLOY_API_KEY!,
    },
  },

  project: {
    name: "my-app",
  },

  environments: {
    production: {
      provider: "dokploy",

      applications: [{
        name: "api",
        source: { type: "github", repo: "myorg/api", branch: "main", owner: "myorg" },
        build: { type: "dockerfile", context: "." },
        domains: [{ host: "api.example.com", https: true }],
        env: {
          NODE_ENV: "production",
          DATABASE_URL: "${{db.postgres.connectionString}}",
        },
        ports: [{ container: 3000 }],
      }],

      databases: [
        { name: "postgres", type: "postgres", version: "16" },
      ],
    },
  },
};

No imports needed. The CLI validates the config at runtime.

To use Railway instead, swap the provider:

providers: {
  railway: {
    type: "railway",
    token: process.env.RAILWAY_TOKEN!,
    teamId: "optional-workspace-id",  // optional
  },
},

The rest of the config (applications, databases, domains) stays the same. See Platform differences for what each provider supports.

4. Preview and apply:

dac plan     # show what would change
dac apply    # apply the changes

5. Deploy:

dac deploy          # deploy all applications
dac deploy api      # deploy a specific app

TypeScript autocomplete (optional)

If you want autocomplete and type checking in your config, add dockyard-cli as a dev dependency in a JS/TS project:

bun add -d dockyard-cli

Then add a type annotation to your config:

import type { DacConfig } from "dockyard-cli";

export default {
  // full autocomplete here
} satisfies DacConfig;

This is optional. The config works without it.

Commands

| Command | Description | |---|---| | dac init | Create a dac.config.ts template | | dac plan | Show planned changes without applying | | dac apply | Apply changes (prompts for confirmation) | | dac apply --auto-approve | Apply without confirmation | | dac deploy [app] | Trigger deployment for one or all apps | | dac destroy | Delete all managed resources | | dac status | List managed resources and their IDs | | dac rollback <app> | Rollback an application |

Configuration reference

Provider types

  • dokploy — Self-hosted Dokploy instance. Requires url and apiKey.
  • railway — Railway.com. Requires token. Optional teamId for workspace scoping.

Source types

  • github - repo, branch, owner, buildPath, watchPaths, triggerType
  • gitlab - repo, branch, owner, buildPath, projectId, pathNamespace
  • bitbucket - repo, branch, owner, repositorySlug, buildPath
  • gitea - repo, branch, owner, buildPath
  • git - url, branch, buildPath, sshKeyId
  • docker - image, registryUrl, username, password

Build types

  • dockerfile - dockerfile, context, buildStage
  • nixpacks - no extra options
  • buildpacks - version
  • static - publishDirectory, isSpa
  • railpack - version

Database types

postgres, mysql, mariadb, redis, mongo

Each takes name, type, and an optional version. Credentials are auto-generated if not specified.

Resource references

Use ${{db.<name>.<field>}} in environment variables to reference database connection details. These are resolved after databases are created.

env: {
  DATABASE_URL: "${{db.postgres.connectionString}}",
  REDIS_URL: "${{db.cache.connectionString}}",
}

Other resource types

Applications can also include: domains, ports, mounts, redirects, security, resources (CPU/memory), replicas.

Top-level config also supports certificates and registries arrays.

Platform differences

Not all features are available on every provider:

| Feature | Dokploy | Railway | |---|---|---| | Applications | Yes | Yes | | Databases | Yes | Yes (auto-created as services) | | Compose | Yes | No | | Domains | Yes | Yes (SSL automatic) | | Mounts/Volumes | Yes | Yes | | Redirects | Yes | No | | Basic auth | Yes | No | | Manual certificates | Yes | No (SSL automatic) |

Using an unsupported feature with a provider that doesn't support it will produce an error during dac plan.

GitHub Actions

Since dac.config.ts is just TypeScript, it can read process.env directly. Any environment variable you set in your GitHub Actions workflow is available in your config. This means you can store secrets (API keys, database passwords, tokens) in GitHub and have them flow into your deployments without hardcoding anything.

Basic setup

Create .github/workflows/deploy.yml:

name: Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2

      - name: Plan
        if: github.event_name == 'pull_request'
        run: bunx dockyard-cli plan
        env:
          DOKPLOY_URL: ${{ secrets.DOKPLOY_URL }}
          DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }}
          STRIPE_KEY: ${{ secrets.STRIPE_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

      - name: Apply
        if: github.event_name == 'push'
        run: bunx dockyard-cli apply --auto-approve
        env:
          DOKPLOY_URL: ${{ secrets.DOKPLOY_URL }}
          DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }}
          STRIPE_KEY: ${{ secrets.STRIPE_KEY }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

      - name: Deploy
        if: github.event_name == 'push'
        run: bunx dockyard-cli deploy
        env:
          DOKPLOY_URL: ${{ secrets.DOKPLOY_URL }}
          DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }}

Then in your config, reference them:

applications: [{
  name: "api",
  // ...
  env: {
    STRIPE_KEY: process.env.STRIPE_KEY!,
    OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
  },
}],

Add your secrets in your GitHub repo under Settings > Secrets and variables > Actions.

Scoped environments (staging / production)

GitHub Actions has an environments feature that lets you define separate sets of secrets per environment. Each environment gets its own secrets, so STRIPE_KEY in staging can be a test key while production uses the live key.

name: Deploy

on:
  push:
    branches: [main, develop]

jobs:
  staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - name: Apply staging
        run: bunx dockyard-cli apply --auto-approve
        env:
          DOKPLOY_URL: ${{ secrets.DOKPLOY_URL }}
          DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }}
          STRIPE_KEY: ${{ secrets.STRIPE_KEY }}
          DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
          APP_ENV: staging
      - name: Deploy staging
        run: bunx dockyard-cli deploy
        env:
          DOKPLOY_URL: ${{ secrets.DOKPLOY_URL }}
          DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }}

  production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - name: Apply production
        run: bunx dockyard-cli apply --auto-approve
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
          STRIPE_KEY: ${{ secrets.STRIPE_KEY }}
          DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
          APP_ENV: production
      - name: Deploy production
        run: bunx dockyard-cli deploy
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}

Your config can then branch on APP_ENV or use different providers per environment. For example, Dokploy for staging and Railway for production:

export default {
  providers: {
    dokploy: {
      type: "dokploy",
      url: process.env.DOKPLOY_URL!,
      apiKey: process.env.DOKPLOY_API_KEY!,
    },
    railway: {
      type: "railway",
      token: process.env.RAILWAY_TOKEN!,
    },
  },

  project: { name: "my-app" },

  environments: {
    staging: {
      provider: "dokploy",
      applications: [{
        name: "api",
        source: { type: "github", repo: "myorg/api", branch: "develop", owner: "myorg" },
        build: { type: "dockerfile" },
        env: {
          NODE_ENV: "staging",
          STRIPE_KEY: process.env.STRIPE_KEY!,
        },
      }],
      databases: [
        { name: "postgres", type: "postgres", version: "16" },
      ],
    },
    production: {
      provider: "railway",
      applications: [{
        name: "api",
        source: { type: "github", repo: "myorg/api", branch: "main", owner: "myorg" },
        build: { type: "dockerfile" },
        env: {
          NODE_ENV: "production",
          STRIPE_KEY: process.env.STRIPE_KEY!,
        },
      }],
      databases: [
        { name: "postgres", type: "postgres", version: "16" },
      ],
    },
  },
};

The same database and application config works on both providers. Dockyard handles the platform-specific translation.

To set this up:

  1. Go to your GitHub repo > Settings > Environments
  2. Create staging and production environments
  3. Add secrets to each (same key names, different values)
  4. Push to develop to deploy staging, push to main to deploy production

The same config file handles both. The secrets are different per environment because GitHub injects the right set based on the environment: field in the workflow.

The .dac/state.json file should be committed to your repo so CI knows what resources are already managed.

How it works

Dockyard keeps a state file at .dac/state.json that maps config resource names to remote IDs. On dac plan or dac apply, it diffs your config against this state and produces creates, updates, and deletes. Resources are applied in dependency order: projects, then environments, then databases, then applications.

Commit the state file to your repo. This is how Dockyard tracks what it manages.

Development

git clone https://github.com/Nu11ified/Dockyard.git
cd Dockyard
bun install
bun test           # run tests
bun run dev        # run CLI without compiling
bun run build      # compile to ./dist/dac

License

MIT