Frameworks & Languages

When to Write a Service in Go Alongside Your Existing Stack

Most of the Go we write does not replace anything. It sits beside a Laravel, Node.js or Python application and does one job the main stack does badly: a queue that never catches up, a hot endpoint, or a burst of outbound calls. Here is how we decide whether a Go service is worth it, how to keep its boundary narrow, and when to leave it alone.

Close-up of a brass gavel and sound block against a dark background

Most of the Go we write does not replace anything. It sits beside an existing Laravel, Node.js or Python application and does one job that the main stack does badly: working through a queue, absorbing a high-volume endpoint, or fanning out hundreds of calls to other systems at once. Done well, the rest of the system barely notices it is there, except that the job now gets done.

Through our Go, Rust and Elixir development service we are asked to write Go services fairly often, and part of the job is saying so when one would not help. This is how we decide.

Signs a Go Service Would Help

These are the situations where a small Go service tends to pay for itself:

  • A queue that never catches up. PHP and Python workers typically handle one job per process, each holding a full copy of the framework in memory, so a growing backlog means more servers. A Go worker handles many jobs concurrently in one process using goroutines, with a fraction of the memory.
  • Work that mostly waits on other systems. Sending thousands of webhooks, checking stock with dozens of suppliers, calling a slow third-party API for every row of an import. Go makes it straightforward to run these in parallel with sensible limits and timeouts.
  • A hot endpoint. One route, often an ingestion or tracking endpoint, takes most of the traffic but does little real work per request. Moving it out can take a large share of load off the main application.
  • A component where determinism and speed both matter. Pricing, matching or rules engines that must give the same answer, quickly, under load.

The last case is one we built for an auction house. On its live auction bidding platform, the real-time saleroom runs on Elixir and Phoenix, but bid validation, increments, reserves, proxy bids and anti-sniping extensions are handled by a dedicated Go service. One service makes every pricing decision in a defined order, so near-simultaneous bids always resolve the same way, and the engine can be tested for correctness separately from the layer that broadcasts bids. The platform holds over 11,000 concurrent bidders on a single sale.

Check the Bottleneck First

Before writing a line of Go, measure. A surprising number of "we need a faster language" conversations end at a missing index or a query inside a loop; we cover the usual causes in why sites slow down as they grow. If each job spends most of its time waiting on the database, a Go worker will wait on the same database, just with more connections open.

Profile a representative job. If the time goes on CPU work, framework start-up or external calls made one after another, Go is likely to help. If it goes on the database, fix the database.

Keep the Boundary Narrow

A side service succeeds or fails on its boundary far more than on its language. Good boundaries are small and explicit:

  • A queue contract. The main application publishes a message with a documented, versioned shape; the Go worker consumes it and reports the result. Neither needs to know how the other is built.
  • An HTTP or gRPC API with a typed contract, for services that answer requests.
  • Its own data, where possible. A Go service writing straight into tables owned by a Laravel application will break the day someone adds a column or a model event the Go code knows nothing about.

If the Go service needs to understand your whole domain model, the boundary is in the wrong place, or the work belongs in the main application after all. Designing these contracts is a core part of our API development and integration work.

What Operational Simplicity Really Means

Go's biggest practical advantage is not raw speed. A Go service compiles to a single binary with no runtime to install, so the container image can be tiny, it starts almost instantly, and memory use is low and predictable. That makes it cheap to run, easy to scale up and down, and free of a dependency tree on the server that drifts out of date.

The simplicity has to be earned with a few habits we build into every service:

  1. Graceful shutdown: stop accepting work on SIGTERM, finish what is in flight, then exit, so deployments never drop jobs.
  2. Timeouts and cancellation on every outbound call, using Go's context package, so one slow dependency cannot pile up thousands of stuck goroutines.
  3. Bounded concurrency. "Run everything in parallel" will happily open ten thousand connections to a supplier whose API allows ten.
  4. Metrics and health endpoints from day one, with the built-in profiler available behind authentication.
  5. A README your existing team can follow to build, deploy and debug the service.

The service should deploy through the same pipeline as the rest of your stack; our Docker and Kubernetes work covers both the containers and the release process.

When Not to Write It in Go

  • Business logic with many rules and screens. Admin interfaces, CRUD and workflows full of special cases are quicker to build and change in a full framework such as Laravel or NestJS. Go's deliberate plainness turns into verbosity.
  • Nobody else can maintain it. A service only one person understands is a risk, however fast it runs. Go is easy to learn, but someone on your team or ours needs to own it.
  • The volume is not there yet. If the current workers keep up with a sensible number of processes, a second language adds cost without benefit. Revisit when the numbers change.
  • The problem is the database. See above.

For the wider comparison of Go with Rust and Elixir, our earlier article on when specialist languages are worth it covers where each one fits.

A Quick Decision Checklist

  1. Have you measured where the time goes, and is it something other than the database?
  2. Can the job be described as a clear input and output, with a narrow contract?
  3. Is the volume high enough that the current approach costs real money or misses deadlines?
  4. Is there someone who will own the service after it ships?

Four yeses make a strong case. If you have a queue that keeps growing or an endpoint that dominates your server bill, send us the numbers: jobs per hour, time per job and what each one waits on. We will tell you whether Go is the answer or whether the fix is somewhere cheaper.

Frequently Asked Questions

Can a Go service share a database with our existing application?

It can, but it is the most common source of trouble. If both write to the same tables, every schema change has to be coordinated across two codebases, and logic such as model events or validation in the main application is silently bypassed. Where sharing is unavoidable, limit the Go service to reading, or to writing its own tables, and treat the schema as a published contract with versioned changes.

How do a Go service and a PHP or Node.js application usually communicate?

Most often through a message queue such as Redis, RabbitMQ or Kafka, with the main application publishing jobs and the Go service consuming them. For request-and-response work, a small HTTP API or gRPC is typical. Queues are usually the better starting point because they decouple the two sides: either can be deployed, restarted or scaled without the other noticing, and a backlog simply waits rather than causing errors.

Is Go hard for an existing PHP, Python or JavaScript team to learn?

Go is one of the easier languages to pick up. It is deliberately small, has one standard formatting style and a strong standard library, and experienced developers usually become productive within a few weeks. The harder part is learning to use concurrency safely, with timeouts, cancellation and limits. A good handover includes documentation, tests and a walkthrough of how the service behaves under failure, not just the code.

How much faster will a Go worker be than our current workers?

It depends entirely on where the time goes. For work that waits on external calls or is limited by memory per process, a Go worker can handle far more jobs on the same hardware because it runs many at once in a single process. For work bound by database queries, the gain may be close to nothing. Profiling a representative job first gives a realistic estimate before anyone commits to a rewrite.

How We Can Help

Services Related to This Article

The work we do with the technologies discussed above — with pricing, process and real examples on each page.

  • Go, Rust & Elixir Development

    Services where throughput, latency or concurrency matter — Go APIs and workers, Rust for performance-critical code, Elixir and Phoenix for real-time systems.

  • API Development & Integration

    Custom REST and GraphQL API development plus integrations with CRMs, ERPs, payment gateways, shipping carriers and marketing platforms.

  • Docker & Kubernetes

    Applications packaged in Docker, deployed with CI/CD, and run on Kubernetes when they need to scale — with monitoring, secrets and rollbacks built in.

  • PHP & Laravel Development

    Laravel web applications, custom PHP development, admin panels, APIs and legacy PHP upgrades — secure, well-structured and easy to maintain.

In Practice

Case Studies on This Topic

Projects where we put these ideas to work, each with a live demo.

  • Living Room — Ashcroft Lettings
    • Laravel
    • PHP 8
    • Blade & Livewire

    Web Application Development

    Property Management & Tenant Portal

    A Laravel platform managing 1,140 units — tenancies, maintenance jobs, contractor scheduling and owner statements.

  • Antique Watch — Ridgemont Auctions
    • Elixir
    • Phoenix Channels
    • Go

    Real-Time Web Platform

    Live Auction Bidding Platform

    An Elixir and Go platform holding 11,000+ concurrent bidders per sale with bid latency measured in milliseconds.

  • Bricks Wall — Barrow Building Supplies
    • Node.js
    • NestJS
    • TypeScript

    API & ERP Integration

    ERP to Web Shop Integration

    A NestJS integration layer moving 312,000 messages a day between an ERP, a web shop and the accounts system.

Keep Reading

Let’s Connect

Let’s Build Something Amazing Together

Share your project details and our experts will get back to you within one business day with the best solution — free consultation, no obligation.