A solo developer has an unusual infrastructure problem: there is nobody else to hand work to.
You are the person writing a feature, reviewing the pull request, repairing the deployment, checking the database migration, answering support email, and wondering why a background job stopped at 02:13. The cost of every repeated decision lands on the same person.
That is why platform engineering matters for solo developers. Not because a one-person project needs an internal cloud department, but because repeated delivery work deserves a reliable default.
The useful goal is not to build a platform team. It is to build a paved road: an opinionated path from source code to a running application that makes the safe choice the easy choice.
A good solo platform answers routine questions before they interrupt your work:
- How does a new service get built and deployed?
- Where do configuration and secrets live?
- How are database migrations applied?
- What does a healthy application look like?
- How do logs, backups, and rollback work?
- What must be true before production changes are allowed?
If each repository answers those questions differently, you do not have flexibility. You have an accumulating support queue with one engineer assigned to it.
Treat the platform as a product you consume
In a large organization, platform engineering is often described as creating self-service capabilities for application teams. For a solo developer, the application team and platform customer are both you—but that distinction remains valuable.
Your future self is the customer.
They will arrive months from now, after context has faded, with an urgent bug report and limited patience. They need a clear route to inspect, change, test, deploy, and recover the system. A platform is successful when that future self can act without rediscovering every operational decision.
This changes how you evaluate tools. Do not ask, “Is this technology powerful?” Ask:
“Will this reduce the number of things I must remember during a production incident?”
That question often favors boring components with excellent defaults over sophisticated systems that demand constant tuning.
For example, a Docker Compose stack on a single Linux host may be a better platform than Kubernetes for a small product. Conversely, a small k3s cluster can be sensible when you run multiple independent services and want consistent networking, health checks, deployments, and workload isolation. The correct choice is the one with the lowest total cognitive load for your actual workload.
Start with a service contract, not infrastructure
The most effective platform artifact for a solo developer is often not a cluster configuration. It is a service contract.
A service contract defines the minimum behavior every deployable application must provide. Keep it short enough that you will actually follow it. For a web API or application, it might require:
- A reproducible Docker image build.
- Environment-driven configuration using documented variable names.
- A
/healthendpoint that verifies process health. - Structured logs written to standard output.
- A documented database migration command.
- A non-root container process.
- A CI workflow that runs tests and builds the image.
This contract creates consistency without requiring every project to share the same framework. A .NET API, a Next.js frontend, and a Node.js worker can use different runtimes while still fitting the same operational shape.
For a .NET service, the contract might mean ASP.NET Core health checks, JSON console logging, and an EF Core migration step. For a Node.js service, it might mean an Express health route, structured logging, and a migration command managed by the application’s database library. The implementation differs; the operational interface remains predictable.
Once the contract is stable, turn it into templates. A repository template or starter directory can include:
The purpose of a template is not to eliminate thought. It is to avoid spending thought on decisions you have already made successfully.
Make delivery a narrow, visible path
A solo delivery system should be deliberately narrow. There should be one obvious path to production, and it should leave evidence behind.
GitHub Actions is often enough for this. A practical pipeline can have four stages:
- Validate: format, lint, and run unit tests.
- Build: create a versioned Docker image.
- Publish: push the image to a registry.
- Deploy: update the runtime environment using a protected production workflow.
Avoid a pipeline that deploys from a developer laptop. Manual commands are fast once, but they create an invisible second deployment mechanism. Later, you will not know whether production matches Git, which image is actually running, or which environment variable was changed during a late-night fix.
Use immutable image references whenever possible. A deployment should reference app:1.8.3 or a Git commit SHA, not merely app:latest. The difference feels minor until a rollback is necessary. With immutable versions, rollback becomes a deliberate selection of a previous known artifact rather than an investigation.
A lightweight deployment record is also valuable. This can be a GitHub Actions summary, a release note, or a simple text file committed alongside deployment configuration. Record the image version, deployment time, migration status, and any manual intervention. Your platform does not need enterprise change management; it needs enough history to answer “what changed?” quickly.
Put operational knowledge next to the code
The most durable solo platform documentation is short, local, and executable.
Every repository should have an operations.md or equivalent document that answers these questions:
- How do I run this locally?
- How do I deploy it?
- How do I inspect logs?
- How do I roll it back?
- How do I back up and restore its data?
- Which external dependencies can cause it to fail?
Do not write a broad architecture novel that becomes outdated after two releases. Write instructions that are useful under pressure. Commands are better than descriptions when commands can be safely copied.
For example, a useful rollback section says:
It does not say “revert the application to a previous stable version.” The latter sounds correct but requires the reader to reconstruct the actual process.
The same principle applies to runbooks. Create them after an incident, not before imaginary ones. If a Redis connection exhaustion incident took thirty minutes to diagnose, capture the checks that would have reduced it to five minutes. Operational documentation should be the fossil record of real pain.
Build observability around questions, not dashboards
Solo developers rarely need an elaborate observability estate on day one. They do need rapid answers to a few questions:
- Is the application up?
- Is it receiving traffic?
- Are errors increasing?
- Is the database reachable?
- Did the latest deployment cause the problem?
Start with health checks, centralized logs, uptime monitoring, and basic resource metrics. If you run containers behind Traefik, make sure you can distinguish a routing failure from an application failure. If your application depends on PostgreSQL or Redis, expose enough application-level logging to identify connection errors, migration failures, and timeouts.
Alert on conditions that require action. An alert for a failed deployment, an unreachable endpoint, or a nearly full disk is useful. An alert for every transient warning is a machine for training yourself to ignore alerts.
A helpful rule is: every alert should have a named first response. If you cannot state the first response, it is probably a dashboard metric rather than an alert.
Design backups as recovery exercises
Backups are not a platform feature until restoration has been tested.
For databases, automate backups, retain them outside the primary machine, and periodically restore one into a disposable environment. For PostgreSQL, that may mean scheduled logical dumps or physical backups, plus a documented restore command. For uploaded files, it may mean object storage replication or a versioned backup target.
The crucial test is not “did the backup job succeed?” It is “can I recover a working service within an acceptable time?”
Write down a recovery objective that fits the project. A personal tool may tolerate a day of recovery time. A paid application may not. This decision informs whether you need snapshots, off-site copies, high-frequency backups, or simply a disciplined nightly export.
Know when to stop platform work
Platform engineering creates leverage, but it can also become a highly respectable form of procrastination.
A useful boundary is to automate a task after it has happened repeatedly, caused an error, or interrupted focused product work. Do not build a generalized internal developer portal for three repositories. Do not add Kubernetes operators because a deployment script feels inelegant. Do not turn every configuration value into a reusable abstraction.
The platform should remain smaller than the products it supports.
For a solo developer, the best platform is not the most advanced stack. It is a collection of defaults that makes shipping ordinary changes calm, makes failures diagnosable, and makes recovery possible without relying on memory.
Build the road. Pave the dangerous turns. Add signs where you have been lost before. Then spend the reclaimed time building the thing users came for.
No comments yet. Be the first to share your thoughts!