DevOps for Series A Startups: What to Build First
A Series A changes the shape of your engineering problems before it changes the size of your team. The product still works. The same three people still know how everything fits together. But now there is a board deck with a hiring plan in it, a couple of enterprise deals that come with security questionnaires, and a runway long enough that "we will fix it later" has quietly become a decision rather than an accident.
The pressure to "do DevOps properly" usually arrives as a shopping list: Kubernetes, a service mesh, multi-region, an internal developer platform, a platform team. Almost none of that is the right first move. What follows is what actually matters between roughly 8 and 30 engineers, what to postpone, and how to think about hiring versus outsourcing versus doing nothing yet.
What actually breaks at this stage
The failures are boring and predictable, and they are almost never about scale.
Deployment becomes contested. At five engineers, one person deploys when the tests look fine. At fifteen, two teams want to ship on the same afternoon, someone reverts someone else's migration, and the fix is a Slack thread instead of a process.
One person is the runbook. There is a founding engineer who knows why the NAT gateway is configured that way, which environment variable the worker actually reads, and how to restart the thing that gets stuck on Sundays. That person is now a manager, or interviewing candidates, or on a plane.
Environments drift. Staging was created by hand in the console eighteen months ago. Production was created by hand too, differently. Nobody can say with confidence what the difference is, so staging stops being evidence of anything.
Credentials sprawl. A shared AWS IAM user with an access key pasted into three laptops and a CI provider. A database password in a pinned Slack message. Nobody has rotated anything, and nobody can tell you who has access to customer data. This is the item that blocks enterprise deals, not your uptime numbers.
Nobody has restored a backup. Automated snapshots are enabled, which is not the same as knowing you can bring the database back. Untested backups are a belief, not a control.
Alerting is either silent or useless. Either you find out about outages from customers, or you have 40 alerts a day and everyone has muted the channel.
Each of those is fixable in days or weeks. None of them requires Kubernetes.
The minimum viable platform
Six things. In this order.
1. One repeatable path to production
Every deploy goes through the same pipeline, triggered by a merge to the main branch, with no human running commands on their laptop. The pipeline should use short-lived cloud credentials, not a stored access key. On AWS and GitHub, that means OIDC.
name: deploy
on:
push:
branches: [main]
permissions:
id-token: write # required for OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/github-deploy
aws-region: eu-west-1
- id: ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, push, deploy
env:
REGISTRY: ${{ steps.ecr.outputs.registry }}
TAG: ${{ github.sha }}
run: |
set -euo pipefail
IMAGE="$REGISTRY/api:$TAG"
docker build -t "$IMAGE" .
docker push "$IMAGE"
NEW_TD=$(aws ecs register-task-definition \
--cli-input-json "$(jq --arg img "$IMAGE" \
'.containerDefinitions[0].image = $img' task-def.json)" \
--query 'taskDefinition.taskDefinitionArn' --output text)
aws ecs update-service --cluster prod --service api \
--task-definition "$NEW_TD"
aws ecs wait services-stable --cluster prod --services api
Two details matter more than the platform choice. The image tag is the commit SHA, so any running container maps back to exact source. And the job waits for the service to stabilise, so a red pipeline means a failed deploy rather than a successful upload.
2. Infrastructure as code, starting with the parts that hurt
You do not need to import every hand-made resource on day one. Codify the things that are painful to recreate and dangerous to change: networking, IAM, databases, DNS, and the CI role itself. Leave the S3 bucket someone made in 2024 for later.
terraform {
backend "s3" {
bucket = "acme-tfstate"
key = "prod/terraform.tfstate"
region = "eu-west-1"
encrypt = true
use_lockfile = true # S3-native locking, no DynamoDB table needed
}
}
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
}
data "aws_iam_policy_document" "github_assume" {
statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = [aws_iam_openid_connect_provider.github.arn]
}
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = ["sts.amazonaws.com"]
}
# Scope to one repo and one branch. Without this condition any
# GitHub repository in the world can assume the role.
condition {
test = "StringLike"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:acme/api:ref:refs/heads/main"]
}
}
}
resource "aws_iam_role" "github_deploy" {
name = "github-deploy"
assume_role_policy = data.aws_iam_policy_document.github_assume.json
}
The sub condition is the one people get wrong. A trust policy that only checks the audience is effectively public.
3. Observability that answers three questions
Not dashboards. Three questions: is it broken, what changed, and where is the time going. In practice that is structured logs with a request ID, error tracking wired to a real channel, and latency and error rate per endpoint. A hosted tool is the right answer here. Running your own metrics and log storage at this size costs more engineering time than it saves in licence fees, and it fails at the worst moment because nobody owns it.
4. On-call that a person can survive
Two or three people in rotation, a written escalation path, and a rule that every page must be actionable. If an alert fires and the response is "yeah, that happens", either fix the thing or delete the alert. A rotation of one is not a rotation, it is a single point of failure with a phone.
5. Backups you have actually restored
Snapshots enabled is step one. Step two is a restore rehearsal you run on a schedule, ideally in CI, so it cannot rot.
set -euo pipefail
SNAPSHOT=$(aws rds describe-db-snapshots \
--db-instance-identifier prod-postgres \
--snapshot-type automated \
--query 'reverse(sort_by(DBSnapshots, &SnapshotCreateTime))[0].DBSnapshotIdentifier' \
--output text)
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier restore-test \
--db-snapshot-identifier "$SNAPSHOT" \
--db-instance-class db.t4g.medium \
--no-publicly-accessible
aws rds wait db-instance-available --db-instance-identifier restore-test
# Prove the data is real, not just that the instance booted.
psql "$RESTORE_URL" -c "select count(*), max(created_at) from orders;"
aws rds delete-db-instance --db-instance-identifier restore-test \
--skip-final-snapshot
Write down how long that took. That number is your recovery time objective, and it is the honest answer when a customer asks.
6. Access control you can explain
SSO for the cloud console, individual identities instead of shared logins, a secrets manager instead of environment variables copied between people, and no long-lived access keys in CI. This is unglamorous and it is the work that turns a security questionnaire from a two-week scramble into a form-filling exercise.
What is premature right now
| Thing | Why teams want it | Why it can wait |
|---|---|---|
| Kubernetes | It is what "real" infrastructure looks like | Unless you already run many services or need its scheduling, ECS Fargate, Cloud Run, or a managed PaaS gets you there with a fraction of the operational surface |
| Service mesh | Observability and mTLS between services | You probably have three services. A load balancer and good logging cover it |
| Multi-region active-active | An enterprise prospect asked | It multiplies data consistency problems and cost. A tested restore and a documented recovery objective answer the actual question |
| Internal developer platform | Deploys feel manual | A platform is an abstraction over repeated pain. Have the repetition first |
| Dedicated platform team | The org chart says so | Pulling two engineers off product to run a platform for twelve people is usually net negative until roughly 25 to 40 engineers |
| Splitting the monolith | It feels crowded | Service boundaries chosen before you understand the domain become distributed versions of the same coupling, with network calls added |
The pattern: these are all solutions to coordination problems that appear when many teams share infrastructure. At Series A you usually have one or two teams. Buying the solution before you have the problem means paying the operating cost without the benefit.
A realistic order of operations
Roughly a quarter of work, mostly sequential because each step makes the next one cheaper.
- Weeks 1 to 2. Access control and secrets. Kill shared credentials and long-lived keys. This is also the highest-value item for sales.
- Weeks 2 to 4. CI/CD to production for the main service. One path, commit-tagged images, automatic rollback or at least a one-command revert.
- Weeks 4 to 7. Infrastructure as code for networking, IAM, data stores, DNS. Rebuild staging from that code to prove it works.
- Weeks 6 to 9. Observability and alerting. Error tracking, structured logs, a small set of alerts tied to customer-visible symptoms.
- Weeks 9 to 11. Backups, restore rehearsal, written recovery objectives.
- Weeks 11 to 13. On-call rotation, runbooks for the five things that actually break, a short incident review habit.
Cost control belongs somewhere in there too, but as a habit rather than a project: tagging, a budget alarm, and a monthly look at the top five line items.
Hire, outsource, or defer
There is no universally correct answer, and the honest framing is about what you are buying.
| Option | Fits when | Real cost | Where it goes wrong |
|---|---|---|---|
| Hire a platform or DevOps engineer | Infrastructure work is continuous, not a project. You have a technical hiring loop and someone senior to manage them | Salary plus recruiting time, typically 2 to 4 months from opening the role to productive output | You hire one person, they become the single point of failure you were trying to remove, and they get bored if the work is 80% maintenance |
| Outsource to a service or fractional team | You have a known gap to close in a defined window, and product engineers are the constraint | Monthly fee, plus your own time on context transfer | Nobody on your side owns the outcome. Without a named internal counterpart, you get artefacts you cannot maintain |
| Defer | Deploys are not blocked, no customer is asking for security evidence, fewer than about eight engineers | Compounding interest. The cleanup gets more expensive as more is built on the shortcut | It stops being a choice. You notice when an outage or a deal forces the work at the worst possible time |
A pattern that works well: outsource the build, own the operation. Bring in help to set up the pipeline, the Terraform, the alerting and the on-call structure, then have your own engineers run it day to day with the option to call for help on the hard parts. That avoids the two common failure modes, which are hiring a specialist to do six weeks of setup and then two years of waiting, and handing your infrastructure to an outside party with no internal understanding of it.
When not to buy this from us
Straightforwardly: if you have fewer than about eight engineers and your app is a single service on a managed platform, you probably do not need us yet. Spend two engineer-weeks on CI/CD, a secrets manager, and a restore test, and get back to product.
If you already have a strong infrastructure-minded engineer with time to spend, you do not need us either. Give them the list above and a quarter.
And if what you actually want is someone to hand a problem to permanently, with no internal owner, that arrangement does not work well with anyone, us included. External help is good at building and unblocking. It is a poor substitute for someone inside the company who cares whether the system stays healthy.
If none of those apply, and you are staring at a quarter of infrastructure work that would come straight out of your product roadmap, that is the case where bringing in a fractional DevOps team is the cheaper trade. We are happy to look at what you have and tell you which parts of the list you can skip, including the parts we would not charge you for.
Top comments (0)