Blog
The Real Full Stack: From Maxwell to the Browser
Full stack doesn't start at the backend. It starts at Ohm's law: hardware design, HIL testing, firmware, buses - and only then the web.
Ask a full stack developer where their stack ends and you will usually get one of two answers. The common one is React on the front, an API on the back, a database somewhere behind it. The more experienced answer adds the operational layer: caching, Postgres tuning, microservices, load balancers, a cloud provider holding it all up. Both answers are fine as far as they go. Both stop at the operating system, and usually well above it.
The stack does not stop there. It does not even start there. Below the lowest layer that most full stack developers ever touch, there are entire engineering disciplines, each with their own design processes, test infrastructure, and deployment pipelines. The stack starts where electrons meet copper, and it is bounded not by a framework’s API surface but by Ohm’s law and Maxwell’s equations. This post is about that stack - the full full stack - and why so few of the people who carry the title have ever seen most of it.
The stack everyone talks about #
The web-era definition of full stack is not wrong, it is just incomplete. It emerged for a good reason: for most software businesses, the interesting engineering problems live between the browser and the database. An engineer who can carry a feature from a UI mockup to a schema migration is genuinely valuable, and the title reflects that.
The problem is that “full stack” quietly became “full web stack”. The layers below - the machine, the board, the physics - got abstracted away so effectively that they disappeared from the mental model entirely. Cloud providers deserve a lot of credit for this: when your compute is a line in a Terraform file, it is easy to forget that somewhere a real board with real voltage regulators is executing your code. The abstraction is the product. But an abstraction being good does not mean the layers beneath it stopped existing.
Where the stack actually starts #
The bottom of the stack is physics. Not “low-level programming” - physics. Current through a conductor obeys . Signals propagating through a circuit board obey Maxwell’s equations, whether or not anyone on the team has heard of them. Past a certain edge rate, a PCB trace stops being a wire and starts being a transmission line: it has impedance, it reflects, it radiates, it couples into its neighbours. A digital signal is only digital in the datasheet; on the oscilloscope it is an analog waveform with rise times, ringing, and noise margins.
This is the layer where the debugging model that software engineers rely on breaks down completely. There is no stack trace for a brownout. There is no redeploy for a via that should have been a through-hole. When a board misbehaves, the bug might be in the code, the schematic, the layout, the power supply, a cold solder joint, or the temperature of the room. The search space is physical, and the fix might require a soldering iron - or a new board revision with a six-week lead time.
Hardware design #
On top of the physics sits hardware design: schematic capture, component selection, PCB layout. Every decision is a trade-off across cost, availability, power, thermals, and manufacturability. Choosing a microcontroller is choosing your compiler, your debugger, your RAM budget, and your interrupt latency for the next five years of the product’s life. Get the decoupling capacitors wrong and you will spend a week chasing “software” bugs that are actually power integrity problems.
The tooling is different too. The hardware engineer’s console.log is a multimeter. The debugger is an oscilloscope. The profiler is a logic analyzer or, for the radiated stuff, a spectrum analyzer in an EMC chamber. These instruments do not lie, but they also do not explain - reading them is a skill that takes years, and it is a skill almost entirely absent from the “full stack” job description.
Hardware-in-the-loop, and CI/CD for it #
Web engineers are rightly proud of their test pyramids and deployment pipelines. Hardware teams have an equivalent that most of the software world has never heard of: Hardware-in-the-Loop testing. A HIL rig connects the real board - real silicon, real firmware - to simulated inputs and instrumented outputs. Sensors are replaced by signal generators, actuators by measurement channels, and the device under test runs against a physics model of the system it will eventually control. It is an integration test where one of the components being integrated is reality.
And yes, this gets wired into CI/CD. A commit to the firmware repository triggers a build, the pipeline flashes the binary onto a rack of physical boards over a debug probe, the HIL rig runs the scenario suite, and power consumption, timing, and bus traffic get checked against limits before the merge goes green. It is continuous deployment where “deployment” means electrons hitting a target board bolted into a test rack. The engineers who build and maintain these rigs are doing DevOps in a world where a flaky test might mean a loose cable.
Firmware, and the applications on top of it #
Above the hardware sits low-level firmware: bare-metal C or an RTOS, memory-mapped registers, interrupt handlers, DMA controllers, linker scripts. There is no operating system to catch you - the firmware is the operating system. Off-by-one on a register offset does not throw an exception; it silently configures the wrong peripheral and you find out three days later on a scope.
On top of that firmware run what are, in every meaningful sense, applications: control loops, state machines, protocol stacks, sometimes a small filesystem or a graphics layer for a local display. They have the same architectural concerns as any backend service - concurrency, scheduling, resource contention, failure recovery - except the heap is 128 KB, the deadline is measured in microseconds, and a crash might be mechanical.
The buses out #
No embedded system is an island. The way it talks to the rest of the world is through its buses, and each one is an escape hatch to a higher layer of the stack: UART for the humble serial console, SPI and I²C for peripherals on the board, CAN for anything that drives or flies, USB and Ethernet for the outside world.
Follow one sensor reading upward and the whole stack lights up. An ADC samples a voltage. Firmware reads it over SPI, filters it, frames it onto a CAN bus. A gateway forwards it over Ethernet to a PC, where a native Win32 or Qt desktop application renders it for an operator - and that application exists because someone below made a bus available and documented its protocol. Push one step further and the same reading lands in a cloud backend, gets cached, load-balanced, and served over HTTPS to a React dashboard. The web stack is real, and it is the last 20 centimeters of a journey that started at a voltage divider.
| The usual “full stack” | The full full stack |
|---|---|
| Frontend | Frontend |
| Backend, database, caching | Backend, database, caching |
| Microservices, load balancers, cloud | Microservices, load balancers, cloud |
| - | Desktop / native applications on external buses |
| - | Connection buses: UART, SPI, I²C, CAN, USB, Ethernet |
| - | Applications running on firmware |
| - | Low-level firmware, RTOS, bare metal |
| - | HIL testing and CI/CD for hardware |
| - | Hardware design: schematics, layout, components |
| - | Physics: Ohm’s law, Maxwell’s equations |
Where the common definition of full stack ends, and where the stack actually ends.
The point #
This is not gatekeeping. Nobody masters all of these layers, and the web layers are not lesser work - distributed systems are genuinely hard, and I am not volunteering to debug anyone’s cache invalidation. The point is about the shape of the map. “Full stack” describes a slice near the top of a much taller column, and the title should carry a quiet asterisk.
Plenty of engineers can write both ends of an HTTP request. Far fewer can look at a schematic and tell you why the board browns out when the motor starts, or sit down with a logic analyzer and find the one byte that a peripheral is clocking out wrong. Those skills are scarcer, they take longer to build, and they sit on the same stack your JSON travels through every day. If you call yourself full stack, take that as an invitation: the rest of the stack is down there, it is physical, and it is a lot of fun.