Skip to content
ShipFastDev
All posts

Article

CI/CD for a small team: the pipeline to have before you launch

, 6 min read

Aymane handles DevOps and cloud work on ShipFastDev projects, joining when a project needs it.

For a small team, the right CI/CD pipeline is short and dull. Every push builds the app and runs the tests in about ten minutes. Every merge to the main branch deploys to a staging copy automatically. Production gets one deliberate step, with a health check and a rollback you have tried at least once. GitHub Actions' free allowance usually covers it (GitLab's 400 free minutes are tight for a busy team), and it is worth having before launch, not after the first bad deploy.

CI and CD in plain terms

Continuous integration means, in Martin Fowler's words, that "each member of a team merges their changes into a codebase together with their colleagues changes at least daily", and each merge is checked by an automated build that includes tests. His list of practices is still the best checklist: keep everything in version control, automate the build, make the build test itself, trigger a build on every push to the main branch, fix broken builds immediately, keep the build fast, and automate deployment.

Continuous delivery takes the next step: every change that passes the pipeline is ready to deploy, and deploying is a routine button press or an automatic step, not an evening of manual work. That is what makes a weekly release rhythm realistic for a small team.

The minimum pipeline, step by step

  1. On every push: install dependencies from the lockfile, run the linter and the unit tests, and build the artifact you will deploy (often a container image). If any step fails, the push is red and fixing it comes first.
  2. On every pull request: the same, plus a short end-to-end smoke test against a running copy of the app. Our Playwright guide covers which three tests to write first.
  3. On merge to main: deploy the exact artifact that passed to staging, run database migrations there, and check that the app answers its health endpoint.
  4. To production: promote the same artifact, not a fresh build, so what you tested is what ships. Run migrations, wait for the health check, and keep the previous version ready.
  5. Rollback: one command or button that puts the previous version back. Try it on staging before you need it on production.

Fowler cites "the XP guideline of a ten minute build" and calls it "perfectly within reason" for most projects. Treat ten minutes as a budget: past it, people stop waiting for the result, and a red build is easy to ignore. Caching dependencies and running independent jobs in parallel usually brings a small project well under it.

Protect production without slowing everyone down

Most of the risk in a pipeline sits in the step that touches production and in the credentials it holds. A few settings cover it:

  • A protected environment. GitHub's deployment environments let you require approval from up to six people or teams, add a wait timer, limit which branches can deploy, and keep secrets that only jobs using that environment can read. Check your plan for private repositories: on GitHub Pro and Team you get deployment branch rules and environment secrets, but required reviewers and wait timers are only available for public repositories on the Free, Pro and Team plans. Without them, a manually triggered production deploy job, restricted to the main branch, gives you the same deliberate step.
  • Least privilege for the pipeline's token. GitHub's security guide says to make sure the GITHUB_TOKEN "is granted the minimum required permissions", with read-only access to repository contents as the default and more only for the jobs that need it.
  • Pinned third-party actions. The same guide recommends pinning actions to a full-length commit SHA rather than a tag, because a tag "can be moved or deleted if a bad actor gains access to the repository storing the action".
  • No secrets in the repository. Keys and passwords live in the CI system's secret store or a secrets manager, never in a committed file.

What it costs

For most small products the answer is close to nothing. GitHub Actions is free for public repositories and for self-hosted runners; for private repositories, GitHub Free includes 2,000 minutes a month and GitHub Team 3,000, with 500 MB and 2 GB of artifact storage. On GitLab.com, free tier namespaces receive 400 compute minutes per month, and paid tiers get more.

A worked example, with the assumptions stated: a 6-minute pipeline, run 10 times a working day, over 22 working days, uses 1,320 minutes a month. That fits inside GitHub Free's 2,000 minutes. The same team on GitLab's free tier would run out in about a week, and would either add a self-hosted runner or move to a paid tier. Real minute counts depend on the runner type and how much of the pipeline runs in parallel, so check your usage page after the first month.

Measure it with the DORA metrics

The DORA research program tracks software delivery with five metrics, split into throughput and instability:

  • Change lead time: the time from a commit to that change running in production.
  • Deployment frequency: how many deployments happen over a period.
  • Failed deployment recovery time: how long it takes to recover from a deployment that needs immediate intervention.
  • Change fail rate: the share of deployments that need immediate intervention.
  • Deployment rework rate: the share of deployments that are unplanned and caused by an incident in production.

You don't need a dashboard to start. A shared note with the date of each production deploy and whether it needed a fix gives you deployment frequency and change fail rate in two minutes a week. If the fail rate climbs, the pipeline is missing a test; if lead time grows, the build or the review step is too slow.

Mistakes that make pipelines useless

  • Ignoring flaky tests. A test that fails one time in ten teaches everyone to re-run instead of read. Fix it or remove it the same week.
  • Rebuilding for production. A new build at deploy time is not the artifact you tested.
  • Manual steps in the middle. A migration or a cache flush that someone has to remember is the step that will be forgotten.
  • No rollback rehearsal. The first time you roll back should not be during an outage.
  • A pipeline nobody owns. Like any code, it needs updates. That upkeep is part of technical debt if it is left alone.

Frequently asked questions

GitHub Actions or GitLab CI?

Use the one that lives where your code already is. Both run the pipeline described here. The practical differences for a small team are the included minutes (2,000 a month on GitHub Free for private repositories, 400 on GitLab.com's free tier, about seven working days at an hour a day) and which features each plan gives private projects.

How long should a CI pipeline take?

Aim for about ten minutes on every push, the guideline Martin Fowler cites. Slower suites, such as long end-to-end runs, can run on merges to main or nightly instead of on every push.

Do we need a staging environment?

For most products, yes. It is where migrations, configuration and the deploy step itself are tested before they reach users. It can be small and can share services with development, but it should be deployed by the same pipeline as production.

Is it safe to deploy to production automatically?

It can be, once your tests are reliable and rollback is one step. A common path is to start with a manually triggered production deploy, or required reviewers where your plan offers them, and to make it automatic once the change fail rate stays low.

Sources

  1. Continuous Integration, Martin Fowler, January 2024
  2. DORA's software delivery metrics, DORA, January 2026
  3. GitHub Actions billing, GitHub Docs, 2026
  4. Managing environments for deployment, GitHub Docs, 2026
  5. Secure use reference, GitHub Docs, 2026
  6. Compute minutes, GitLab Docs, 2026
  7. Deployments and environments, GitHub Docs, 2026

Want this kind of work on your product?

Tell Adil what you’re building. You get a reply within 1 business day with times for a 15-minute video call.