cpplite is a lightweight C++23 template for internal high-performance microservices. It is small, explicit, and production-oriented: gRPC and Protobuf for service contracts, PostgreSQL with visible SQL, modern CMake, vcpkg, Docker, tests, linting, and simple operational defaults.
This is a template, not a framework. It gives a starting shape and a few replaceable examples.
AI coding agents working in this template should start with .agents/README.md.
- Not an HTTP-first web framework.
- Not an ORM or SQL abstraction layer.
- Not a dependency injection framework.
- Not a service mesh, gateway, or Kubernetes template.
- Not a generic enterprise platform.
- CMake 3.25 or newer and Python 3.10 or newer.
- Linux/macOS: a C++23 compiler, Ninja,
bison, andflex. - Windows: Visual Studio 2022 with the Desktop development with C++ workload.
- The in-repo
vcpkgsubmodule. - Docker and Docker Compose for the containerized database and service workflow.
clang-format,clang-tidy, andgrpcurlfor local workflows;psqlwhen applying migrations from the host.- Optional:
ccachefor faster local rebuilds. CMake uses it automatically when present.
Clone with submodules:
git clone --recurse-submodules <repo-url>If the repository is already cloned:
git submodule update --init --recursiveThe host-specific setup scripts install the core compiler and developer tools, initialize and bootstrap vcpkg, and configure the default debug preset. Run the matching script from the repository root:
Windows, from an Administrator PowerShell session:
powershell -ExecutionPolicy Bypass -File scripts/setup-windows.ps1Ubuntu 24.04 or newer:
bash scripts/setup-ubuntu.shmacOS:
bash scripts/setup-macos.shPass --install-docker on Ubuntu/macOS or -InstallDocker on Windows to install Docker too. Docker is opt-in because Windows and macOS require Docker Desktop startup and may require a reboot; Linux users must log in again after being added to the docker group. Pass --skip-configure (-SkipConfigure on Windows) to install and bootstrap without configuring CMake.
The Python task runner uses windows-debug on Windows and debug everywhere else. On Windows PowerShell:
python scripts/dev.py configure
python scripts/dev.py build
python scripts/dev.py test
python scripts/dev.py postgres-up
python scripts/dev.py migrate
python scripts/dev.py runOn Linux or macOS, use the same commands with python3:
python3 scripts/dev.py configure
python3 scripts/dev.py build
python3 scripts/dev.py test
python3 scripts/dev.py postgres-up
python3 scripts/dev.py migrate
python3 scripts/dev.py runIn another terminal:
python3 scripts/dev.py smokepython3 scripts/dev.py --help
python3 scripts/dev.py configure
python3 scripts/dev.py build
python3 scripts/dev.py test
python3 scripts/dev.py format
python3 scripts/dev.py format --check
python3 scripts/dev.py lint
python3 scripts/dev.py verify
python3 scripts/dev.py docker-build
python3 scripts/dev.py ccache-stats
python3 scripts/dev.py ccache-zero
python3 scripts/dev.py cleanCMake remains the source of truth. The Python runner is cross-platform, and the Makefile remains as an optional wrapper for Unix and GNU Make users. Replace python3 with python in the examples on Windows.
Disable automatic ccache use with cmake --preset <preset> -DCPPLITE_ENABLE_CCACHE=OFF.
The Windows presets use the Visual Studio generator, so they work from a normal PowerShell session and place executables under a configuration directory such as build/windows-debug/Debug. The task runner handles that path automatically. Ninja-based presets remain available on Windows when run from a Visual Studio developer shell.
PostgreSQL is provided by Docker Compose:
python3 scripts/dev.py postgres-up
python3 scripts/dev.py migrate
python3 scripts/dev.py runThe service listens on 0.0.0.0:50051 by default.
grpcurl -plaintext \
-d '{"id":"example-1"}' \
localhost:50051 \
cpplite.v1.ExampleService/GetExampleThe standard gRPC health checking service is enabled:
grpcurl -plaintext localhost:50051 grpc.health.v1.Health/CheckSQL migrations live in db/migrations. The repository example uses libpqxx with explicit transactions and visible SQL. There is no ORM.
python3 scripts/dev.py postgres-up
python3 scripts/dev.py migrateConfiguration comes from environment variables, with optional YAML through CPPLITE_CONFIG_FILE.
Important variables:
CPPLITE_SERVICE_NAMECPPLITE_BIND_ADDRESSCPPLITE_PORTCPPLITE_LOG_LEVELCPPLITE_POSTGRES_CONNECTION_STRINGCPPLITE_AUTH_MODECPPLITE_STATIC_TOKENCPPLITE_TLS_ENABLEDCPPLITE_TLS_CERT_CHAIN_PATHCPPLITE_TLS_PRIVATE_KEY_PATHCPPLITE_TLS_ROOT_CERT_PATH
See config/service.example.yaml.
proto/: IDL-first service contracts.src/domain/: dependency-free domain model and errors.src/application/: use cases and ports.src/grpc/: generated-service adapter and protobuf mapping.src/server/: gRPC server startup, metadata, context, and request pipeline.src/middleware/: unary request middleware.src/persistence/: PostgreSQL integration and SQL.src/bootstrap/: explicit wiring.src/observability/: logging and metrics interfaces.tests/: deterministic unit tests plus integration skeletons.
Unary RPCs pass through an application-level pipeline:
using UnaryHandler = std::function<grpc::Status(RpcContext&)>;
using UnaryMiddleware = std::function<grpc::Status(RpcContext&, UnaryHandler)>;Middleware is registered in order, can short-circuit, can read metadata, and can attach request-scoped values. It does not depend on generated protobuf service classes or gRPC experimental interceptors.
Included middleware:
- Request ID.
- Deadline and cancellation checks.
- Structured-ish logging.
- Metrics stub.
- Auth stub.
- Application error mapping.
python3 scripts/dev.py init-template \
--service-name billing-service \
--cpp-namespace acme::billing \
--proto-package acme.billing.v1 \
--docker-image ghcr.io/acme/billing-serviceThen replace the example proto, use case, repository, and service adapter with your real service contract and behavior.