DEV Community

Cover image for Corgi: The CLI That Tames Your Local Microservices Chaos
Andrii Klymiuk
Andrii Klymiuk

Posted on • Edited on

1 1 1

Corgi: The CLI That Tames Your Local Microservices Chaos

Microservices architecture gives us flexibility and scale, but the local development experience? It's a nightmare of tangled dependencies, Docker scripts, and that recurring question: 'How do I seed this database again?'. After one too many onboarding sessions that took hours instead of minutes, I built Corgi, an open-source Go CLI that launches your entire stack with a single command. It's not Docker Compose with a pretty face—it's a fundamentally different approach that containerizes only what needs isolation (databases) while running your services natively for better performance and lower resource usage

In this post, I'll walk you through why I created Corgi, what makes it special, and how it can transform your team's development workflow—all from a simple YAML file.

The Problem: Microservices Development Was Too Chaotic

A while back, I was working on a project with multiple microservices, each with its own database requirements. We faced several challenges:

  • Onboarding new developers took hours of explanation and troubleshooting
  • Database seeding was inconsistent and required manual steps
  • Service dependencies had to be launched in a specific order
  • Environment variables were difficult to manage across services and filled manually

Why

I tried existing solutions like Docker Compose and Kubernetes, but they either felt too heavy or didn't solve our specific problems:

  • Docker Compose is solid but lacks native DB seeding or service orchestration smarts. It also runs everything in containers, which consumes more resources than necessary for local development.
  • Custom Scripts are a maintenance nightmare and don't scale across teams
  • Cloud Tools want your data and your wallet, neither of which I'm keen to hand over

I wanted something that would make running our entire stack locally as simple as a single command, but with the efficiency of running services natively when appropriate. When I couldn't find it, I built Corgi.

What Makes Corgi Special?

Corgi is like a loyal companion that cuts through the chaos. Here's what sets it apart:

  • Define Once, Run Anywhere: Write a corgi-compose.yml file with your services and DBs. One command corgi run and everything launches. Share that file with your team, and they're up in minutes.
  • Database Superpowers: Seed Postgres, MongoDB, Redis (and 30+ others) from SQL dumps or remote DBs. No more manual imports or stale test data.
  • Parallel Power: Services start concurrently, not in some sluggish sequence. Your API and frontend are live at the same time, every time.
  • Auto Git Clone: Repositories specified with cloneFrom are automatically cloned during initialization, ensuring everyone on your team has the exact same code structure. If they were cloned already, they are not cloned again.
  • Smart Environment Management: Automatically connect services with the right environment variables. When you specify dependencies using depends_on_services and depends_on_db, Corgi populates each service's .env file with the correct connection information. For database dependencies, it adds credentials (DB_HOST, DB_USER, etc.), and for service dependencies, it adds URLs like SERVICE_NAME=http://localhost:3000. No more manual environment configuration or copying connection strings.
  • Resource Efficiency: Only containerizes databases while running your services natively, saving significant CPU and memory compared to full containerization
  • Simple YAML Configuration: Describe your entire project in one readable file and check its syntax with dedicated vscode corgi extension

It's not flashy—it's functional.

Getting Started

Ready to give Corgi a spin? Here's how to get started:

  1. Install Corgi with Homebrew:
   brew install andriiklymiuk/homebrew-tools/corgi

   # Check if it works
   corgi -h
Enter fullscreen mode Exit fullscreen mode
  1. Create a simple corgi-compose.yml file in your project with db or services part
  2. Run corgi init followed by corgi run

Want to try an example project? Run:

corgi run -t https://github.com/Andriiklymiuk/corgi_examples/blob/main/honoExpoTodo/hono-bun-expo.corgi-compose.yml
Enter fullscreen mode Exit fullscreen mode

This will download and run a sample Todo app with a Hono backend and an Expo frontend.

Under the Hood: How Corgi Works

Unlike Docker Compose, which containerizes everything, Corgi takes a hybrid approach:

  1. Databases run in Docker: Corgi creates Docker container templates for your databases, making them easy to start, stop, and clean up.
  2. Services run natively: Your actual applications (Node.js servers, Go APIs, React frontends, etc.) run directly on your machine, saving CPU and memory.
  3. Environment auto-wiring: Corgi automatically connects everything by generating the right environment variables and .env files.
  4. Parallel execution: Service commands run concurrently, making startup much faster.

This hybrid approach gives you the best of both worlds: the isolation of Docker for databases with the performance of native execution for your applications.

How I Use It (and Why You'll Love It)

Here's a glimpse of how Corgi fits into my workflow:

  • Team Onboarding: New teammate? Send them the corgi-compose.yml. They run corgi run, and they're coding, not debugging setup.
  • Prototyping: Testing a new service? Clone it, tweak the YAML, and run it alongside the rest. Ports and dependencies sort themselves out.
  • Prod Parity: Seed your local DB from a prod dump. Catch issues before they hit staging.
  • Resource Management: Run a complex stack on a laptop without fans spinning up, since only the databases are containerized.
  • Cleanup: Ctrl+C kills everything cleanly, with optional afterStart commands to tidy up.

Let's look at a simple example:

# corgi-compose.yml
db_services:
  postgres_main:
    driver: postgres
    databaseName: app_db
    user: admin
    password: secret
    port: 5432
    seedFromFilePath: ./seed.sql

services:
  backend:
    cloneFrom: https://github.com/myorg/backend-api.git
    path: ./backend
    port: 8080
    depends_on_db:
      - name: postgres_main
    beforeStart:
      - go mod tidy
    start:
      - go run main.go

  frontend:
    cloneFrom: https://github.com/myorg/frontend-app.git
    path: ./frontend
    port: 3000
    depends_on_services:
      - name: backend
    start:
      - npm run dev
Enter fullscreen mode Exit fullscreen mode

With this file, anyone on your team can run:

# First time setup
corgi init

# Run everything
corgi run
Enter fullscreen mode Exit fullscreen mode

And Corgi will:

  1. Clone both repositories (if they don't exist)
  2. Create and start the Postgres database in Docker
  3. Seed the database from your SQL file
  4. Configure environment variables to connect everything
  5. Start both services concurrently (directly on your machine, not in Docker)
  6. Handle clean shutdown when you hit Ctrl+C

No more "it works on my machine" problems!

Real-World Examples

Example 1: Todo App with Bun and Expo

Here's a simple Todo application setup with React Native/Expo frontend and a Bun-powered backend:

services:
  dodoApp:
    cloneFrom: https://github.com/Andriiklymiuk/dodo.git
    path: ./dodo
    depends_on_services:
      - name: dodoServer
        envAlias: EXPO_PUBLIC_TODO_URL
        suffix: /
    environment:
      - EXPO_PUBLIC_TODO_WEBSOCKET_URL=ws://localhost:65533
    beforeStart:
      - yarn install
    start:
      # you can run yarn startAll to open web, android and ios all at once
      # - yarn startAll
      # or you can run yarn web, yarn ios, yarn android separately
      - yarn ios
    afterStart:
      # close ios emulator
      - killall Simulator 2>/dev/null || true
      # close android emulator
      - killall qemu-system-aarch64 2>/dev/null || true
  dodoServer:
    cloneFrom: https://github.com/Andriiklymiuk/dodoServer.git
    path: ./dodoServer
    port: 65533
    beforeStart:
      - bun install
    start:
      - bun dev
Enter fullscreen mode Exit fullscreen mode

Notice how this configuration handles mobile development cleanly, automatically connecting the Expo app to its backend and even providing cleanup commands to close simulators when you're done.

Example 2: Go and Deno with AWS SQS

This example showcases a Go service that listens to SQS messages sent by a Deno service, with a Postgres database:

db_services:
  postgres-db-for-go-example:
    driver: postgres
    databaseName: best_name_for_database
    user: woof
    password: woof_database_password
    port: 5234
  aws-sqs-queue-for-go:
    driver: sqs
    databaseName: sqs_queue_name
    port: 4599

services:
  go_aws_sqs_listener:
    cloneFrom: https://github.com/Andriiklymiuk/go_aws_sqs_listener.git
    path: ./go_aws_sqs_listener
    depends_on_db:
      - name: postgres-db-for-go-example
        envAlias: none
      - name: aws-sqs-queue-for-go
        envAlias: none
    port: 7092
    start:
      - go run .
  deno_aws_sqs_emitter:
    cloneFrom: https://github.com/Andriiklymiuk/deno_aws_sqs_emitter.git
    path: ./deno_aws_sqs_emitter
    depends_on_db:
      - name: aws-sqs-queue-for-go
        envAlias: none
    port: 7098
    start:
      - deno run --allow-net --allow-read --allow-env server.ts

required:
  go:
    why:
      - To launch locally service manually
      - You need to install it yourself brew install go
    checkCmd: go version
  deno:
    why:
      - Needed to launch deno_aws_sqs_emitter
      - You need to install it yourself from https://deno.land/manual/getting_started/installation
    checkCmd: deno --version
  docker:
    why:
      - To launch databases
      - You need to install it yourself from https://docs.docker.com/desktop/install/mac-install/
    checkCmd: docker -v
Enter fullscreen mode Exit fullscreen mode

This example shows how Corgi handles more complex infrastructure like message queues just as easily as databases, connecting the services together automatically.

Example 3: React Native App with Go Backend and Seeded Postgres

Here's an example that includes database seeding from a dump file:

db_services:
  postgres_with_data_for_go_reactnative:
    driver: postgres
    databaseName: bestDbName
    user: awesomeUser
    password: themostsecurepasswordyoucanimaging
    port: 5511
    seedFromFilePath: ./users_dump.sql

services:
  reactnative_app_get_user:
    cloneFrom: https://github.com/Andriiklymiuk/reactnative_app_get_user.git
    path: ./reactnative_app_get_user
    depends_on_services:
      - name: go_server_user_data
    beforeStart:
      - yarn install
      - npx pod-install
    start:
      - yarn start
      - yarn ios
    afterStart:
      - yarn ios:simulator:close
  go_server_user_data:
    cloneFrom: https://github.com/Andriiklymiuk/go_server_user_data.git
    path: ./go_server_user_data
    port: 7012
    depends_on_db:
      - name: postgres_with_data_for_go_reactnative
        envAlias: none
    start:
      - go run .

required:
  go:
    why:
      - To launch locally go service manually
      - You need to install it yourself brew install go
    checkCmd: go version
  yarn:
    why:
      - To build and launch some of the repos locally with yarn
    install:
      - brew install yarn
    checkCmd: yarn -v
  node:
    why:
      - To build and launch some of the repos locally with npm
    install:
      - brew install node
    checkCmd: node -v
  docker:
    why:
      - To launch databases
      - You need to install it yourself from https://docs.docker.com/desktop/install/mac-install/
    checkCmd: docker -v
Enter fullscreen mode Exit fullscreen mode

For this example, the users_dump.sql file contains a schema and sample data:

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public;

COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';
SET default_tablespace = '';
SET default_table_access_method = heap;

CREATE TABLE public.schema_migrations (
  version bigint NOT NULL,
  dirty boolean NOT NULL
);

CREATE TABLE public.users (
  id uuid DEFAULT gen_random_uuid() NOT NULL,
  name text NOT NULL
);

COPY public.schema_migrations (version, dirty) FROM stdin;
1 f
\.

COPY public.users (id, name) FROM stdin;
0961f8ea-7a94-4f2f-ba09-f41c802465b4 Some random user
0961f8ea-7a94-4f2f-ba09-f41c802465b5 Another random user
\.

ALTER TABLE ONLY public.schema_migrations
  ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);

ALTER TABLE ONLY public.users
  ADD CONSTRAINT users_pkey PRIMARY KEY (id);
Enter fullscreen mode Exit fullscreen mode

To use this configuration:

  1. Download the corgi-compose.yml file and the users_dump.sql file
  2. Run corgi init to initialize repos
  3. Run corgi run --seed to start everything with database seeding

This will start up the iOS app and Go server with a seeded Postgres database containing sample user data.

Example 4: RabbitMQ with NestJS and Go

This example showcases a message queue setup with NestJS sending messages to a Go service:

db_services:
  rabbitmq-for-go-nestjs:
    user: best_user
    password: most_secure_password
    driver: rabbitmq
    databaseName: rabbitmq-for-go-nestjs-db
    port: 4577

services:
  nestjs_rabbitmq_emitter:
    cloneFrom: https://github.com/Andriiklymiuk/nestjs_rabbitmq_emitter.git
    path: ./nestjs_rabbitmq_emitter
    port: 7856
    depends_on_db:
      - name: rabbitmq-for-go-nestjs
    beforeStart:
      - pnpm install
    start:
      - pnpm start:dev
  go_rabbitmq_listener:
    cloneFrom: https://github.com/Andriiklymiuk/go_rabbitmq_listener.git
    path: ./go_rabbitmq_listener
    port: 7854
    depends_on_db:
      - name: rabbitmq-for-go-nestjs
    beforeStart:
      - go run .

required:
  go:
    why:
      - To launch locally sync-go-trigger service manually
      - You need to install it yourself brew install go
    checkCmd: go version
  pnpm:
    why:
      - To launch products service locally
    install:
      - brew install pnpm
    checkCmd: pnpm -v
  docker:
    why:
      - To launch databases
      - You need to install it yourself from https://docs.docker.com/desktop/install/mac-install/
    checkCmd: docker -v
Enter fullscreen mode Exit fullscreen mode

Example 5: Redis with Bun Server and Expo Client

This example shows a Redis-backed application with a Bun server and Expo client:

db_services:
  redis-for-bun:
    driver: redis
    host: localhost
    user: best_user_for_this_serivce
    password: most_secure_password_ever
    port: 2911

services:
  expo_redis_listener:
    cloneFrom: https://github.com/Andriiklymiuk/expo_redis_listener.git
    depends_on_services:
      - name: bun_redis_server
        envAlias: EXPO_PUBLIC_API_URL
    beforeStart:
      - yarn install
    start:
      - yarn ios
    afterStart:
      - yarn ios:simulator:close
  bun_redis_server:
    cloneFrom: https://github.com/Andriiklymiuk/bun_redis_server.git
    port: 1022
    depends_on_db:
      - name: redis-for-bun
    beforeStart:
      - bun install
    start:
      - bun start

required:
  yarn:
    why:
      - To build and launch some of the repos locally with yarn
    install:
      - brew install yarn
    checkCmd: yarn -v
  bun:
    why:
      - To launch products service locally
    install:
      - curl -fsSL https://bun.sh/install | bash
    checkCmd: bun -v
  docker:
    why:
      - To launch database services
      - You need to install it yourself from https://docs.docker.com/desktop/install/mac-install/
    checkCmd: docker -v
  jq:
    why:
      - To format server output in nice format
    install:
      - brew install jq
    checkCmd: jq --version
Enter fullscreen mode Exit fullscreen mode

Database Support: Not Just Postgres

One of my favorite features is Corgi's extensive database support. While the examples above use several different databases, Corgi supports a huge range:

And over 20 more specialized databases like CockroachDB, SurrealDB, and Timescale. You can find the full list and examples in the Corgi documentation.

Each database type comes with sensible defaults, but you can configure them exactly as needed for your project.

Database Helpers: Seeding and Management

Working with databases locally is one of the biggest pain points in microservices development. Corgi makes this easy with built-in database helpers:

Automated Database Seeding

You can seed your databases in two ways:

Automatically (recommended)

# Run with the seed flag
corgi run --seed
Enter fullscreen mode Exit fullscreen mode

This will automatically create dumps and seed your databases based on the configuration in your corgi-compose.yml file.

Manually

If you need more control:

  1. Run corgi db
  2. Choose your service
  3. Select dump to create a dump
  4. Select seed to populate the database

Database Commands

Corgi provides a simple CLI for database management:

# Start all databases
corgi db -u

# Stop all databases
corgi db -s

# Remove all databases
corgi db -r

# Combination: stop, remove, and start all databases
corgi db -rsu
Enter fullscreen mode Exit fullscreen mode

Or work with individual databases using the interactive menu:

corgi db
Enter fullscreen mode Exit fullscreen mode

This gives you an interactive menu to choose your service and the operation you want to perform:

Use the arrow keys to navigate: ↓ ↑ → ← 
? Select service: 
  ▸ 🛑  close program
    postgres_with_data_for_go_reactnative
    rabbitmq-for-go-nestjs
    redis-for-bun
Enter fullscreen mode Exit fullscreen mode

After selecting a service, you'll see connection info and available commands:

Connection info to postgres_with_data_for_go_reactnative:

PORT 5511
USER awesomeUser
PASSWORD themostsecurepasswordyoucanimaging
DB bestDbName

postgres_with_data_for_go_reactnative is running 🟢
Use the arrow keys to navigate: ↓ ↑ → ← 
? Select command: 
  ▸ ⬅️  go back
    down
    help
    id
    listDocker
    seed
    up
Enter fullscreen mode Exit fullscreen mode

Advanced Commands and Options

Corgi offers a range of commands to help manage your development environment:

Selective Running

Want to run just specific services or databases?

# Run only selected services
corgi run --services app,server

# Run only selected databases
corgi run --dbServices postgres,redis

# Skip certain parts of the process
corgi run --omit beforeStart,afterStart
Enter fullscreen mode Exit fullscreen mode

Git Operations

Keep your repositories up to date:

# Pull updates for all service repositories
corgi pull
Enter fullscreen mode Exit fullscreen mode

Service Management

Initialize and clean up as needed:

# Initialize everything from your corgi-compose.yml
corgi init

# Clean all services
corgi clean
Enter fullscreen mode Exit fullscreen mode

Watch Mode

Corgi automatically watches for changes to your corgi-compose.yml file and reloads when changes are detected. If you want to disable this:

# Run without watching for config changes
corgi run --no-watch
Enter fullscreen mode Exit fullscreen mode

Docker Compose vs. Corgi: Why Choose Corgi?

While Docker Compose is a fantastic tool, Corgi addresses several pain points for local development:

  1. Resource Efficiency: Docker Compose runs everything in containers. Corgi only containerizes databases while running your services natively, saving significant CPU and memory.

  2. Simpler Database Management: Corgi has built-in commands for database operations (seeding, dumping, etc.) that would require custom scripts in Docker Compose.

  3. Environment Variable Wiring: Corgi automatically connects services with the right environment variables, handling the tedious .env file management for you.

  4. Service Commands: Corgi can run pre-start, start, and post-start commands for each service, giving you full control over the lifecycle.

  5. Native Performance: Services running directly on your machine often perform better than containerized ones, especially for development tasks like hot reloading.

  6. Smaller Footprint: Corgi itself is a tiny Go binary (~5MB) compared to the Docker ecosystem.

Corgi isn't trying to replace Docker Compose for production deployments—it's focused on making local development smoother and more efficient.

VS Code Integration

If you're a VS Code user like me, you'll love the Corgi Checker extension. It provides:

  • Syntax highlighting for corgi-compose.yml files
  • Command palette integration for common Corgi commands
  • IntelliSense autocompletion for Corgi configuration options
  • Quick access to example templates

The extension makes working with Corgi even more seamless, especially when you're tweaking your configuration.

Why Go?

You might wonder why I built Corgi in Go rather than JavaScript or Python. There were several reasons:

  • Speed: Go is fast and creates small, efficient binaries
  • Cross-platform: Go makes it easy to build for multiple operating systems
  • Simplicity: Go's standard library covers most of what's needed
  • Concurrency: Go's goroutines make it easy to run services in parallel

The result is a lightweight CLI (around 5MB) that starts instantly and efficiently manages your services. The source code is fully open-sourced, so you can contribute or customize it to fit your specific needs.

In Conclusion

Corgi was born out of real developer frustration, and its focused approach to local microservices development has already saved countless hours for me and my fellow developers. By containerizing only what needs isolation while running services natively, it delivers the perfect balance of isolation and performance. As microservices continue to dominate architecture patterns, tools that simplify the local development experience become increasingly valuable. Looking ahead, I plan to extend Corgi with more useful stuff. The goal remains the same: make local development so seamless that you forget it's supposed to be hard.

Why "Corgi"?

I love them to be short)) Cli gets job done—like the dog that stares down chaos and wins. Corgis are loyal, hardworking, and surprisingly powerful for their size—just like this tool. They're also excellent herders, which fits perfectly with the tool's ability to corral multiple services and databases.

I've been using Corgi daily for more than a year, so that's battle tested and today I decided to share it with the world broadly. Whether you're a solo developer juggling multiple projects or part of a team managing a complex microservice architecture, I think you'll find it as helpful as I do.

And if you enjoyed this, you might also like my VS Code extension Golden Retriever for API testing within VS Code. There's even a sneak peek of Corgi at the end of my Golden Retriever demo.

So, what do you think? Grab Corgi from Homebrew, try it out, and let me know your thoughts in the comments. How's your dev setup looking these days?

Let's build smarter. 🚀

Photo by Jarrel Ng on Unsplash

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed
  • 2:34 --only-changed
  • 4:27 --repeat-each
  • 5:15 --forbid-only
  • 5:51 --ui --headed --workers 1

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Top comments (1)

Collapse
 
andriiklymiuk profile image
Andrii Klymiuk

Hi) launched it on product hunt)
producthunt.com/posts/corgi-cli

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay