← All posts
Custom Software
10 min read

How We Built an Offline-First Restaurant POS System

Inside the restaurant POS system we built and still run for Bocconcino Pizza & Donairs in Burlington, Ontario: offline order queuing, kitchen routing, and horizontal scaling across cashier stations.

Software Developer & AI Solutions Engineer ·

The problem with most restaurant POS software

A restaurant POS system has one job it cannot fail at: taking an order. Payments, kitchen routing, and delivery dispatch all matter, but if the till goes down during a dinner rush because the internet dropped for ninety seconds, the restaurant loses money in real time and the staff loses trust in the system.

That was the starting requirement for the restaurant POS system we built and still manage today, live since June 2026 at Bocconcino Pizza & Donairs in Burlington, Ontario: it had to keep taking orders even when connectivity did not cooperate, and it had to scale to as many cashier stations as a location needed without turning every new terminal into an IT project.

Designing for offline first, not offline as an afterthought

Offline support is easy to bolt on badly and hard to get right. We built the POS as a Windows desktop application in Flutter that queues orders locally the moment connectivity drops, then syncs everything back to the server automatically once the connection returns, with no manual reconciliation step for staff to remember.

Under the hood, this meant batched order processing rather than a naive one-request-per-order model, PostgreSQL as the system of record, and Redis for the caching layer that keeps the till responsive even under load. None of that complexity is visible to a cashier. From their side, the screen just keeps working.

Why we built the till itself in Flutter

A POS terminal is not a webpage. It runs the same screens for ten, twelve hours a day, on hardware that varies restaurant to restaurant, and it cannot afford the overhead or occasional hiccups of a browser-based till. Building it as a native Flutter desktop application gave us consistent, predictable performance regardless of what else is running on the machine.

It also meant one shared codebase and one design system across the till itself, without splitting attention across a separate framework for the desktop app and another for everything else we maintain. That consistency is part of why we can keep adding cashier stations for a restaurant without every rollout turning into a custom build.

Why speed at the till comes down to caching

A cashier taking an order during a rush cannot wait even a second or two for a menu item, price, or stock status to load. Every one of those lookups happens constantly through a shift, so if each one had to hit PostgreSQL directly, the till would slow down exactly when it needs to be fastest.

We use Redis as a caching layer in front of the database specifically for this: the data a cashier touches most, menu items, prices, and stock status, gets served from cache instead of being queried fresh every time. PostgreSQL still stays the source of truth for everything, Redis just keeps the hot path fast so the screen responds instantly no matter how busy the restaurant gets.

One ticket flow for pickup, delivery, and walk-in

Every order starts the same way: the cashier picks a ticket type, pickup, delivery, or walk-in, and the till builds the right ticket from there. Rather than three separate flows bolted together, it is one ticket-building screen that adjusts what it asks for based on that choice, so a cashier moving fast during a rush is not relearning the interface depending on how the order came in.

From that screen, building an order is a matter of tapping through menu categories, adding items, and adjusting modifiers, with the running subtotal, tax, and total updating live on the ticket as items go in. The goal is the same one behind the offline-first design: the cashier should never be waiting on the system, the system should be keeping up with the cashier.

Payments without friction: cash, card, tips, and discounts

Settling a ticket supports both cash and card, and cash payments walk the cashier through a dedicated numeric keypad for the amount tendered, with change calculated instantly as they type. Tips and discounts use quick preset buttons for common amounts, a percentage or flat five, ten, or fifteen, alongside a custom option for anything outside those presets, so the common case is fast and the exception is still handled without leaving the screen.

None of this is a separate app bolted onto the ticket screen. It is the same ticket, the same order, carried through to settlement, which is part of why staff can be trained on the till in minutes rather than a full shift.

Kitchen routing, ready orders, and delivery dispatch

Taking the order is only step one. Orders route directly into a kitchen display and ticket workflow so the back of house sees what to make without a printer jamming at the worst possible moment. Once an item is ready, it moves into a dedicated ready-orders queue, where staff can mark it collected, send it back to the kitchen if something needs correcting, or reopen it if a customer's order changes.

Delivery orders move into a separate assign-drivers view once they are ready, split between orders still awaiting a driver and orders already out for delivery. Dispatching a ready order is a matter of selecting a driver and sending it; reassigning an order already out to a different driver takes the same two steps. Every open ticket, regardless of type or status, is also searchable from a single open-tickets list, so nothing gets lost between the kitchen, the till, and the road.

Scaling to more cashier stations without a support call

Restaurants grow, and adding a second or third register during a busy season should not require a technician visit. The system is built to scale horizontally: adding a new cashier station is a matter of installing the software and signing in with an account, nothing more.

A web-based admin panel that puts the owner in control

The till handles the moment of the sale. It should not be where an owner runs the business. Alongside the desktop POS, we built a web-based admin panel in Next.js and Tailwind CSS that gives restaurant owners and managers control over the entire operation from a browser, on any device, without touching a cashier terminal.

  • Menu management: add items, change prices, mark something out of stock, or restructure categories, with changes applying across every connected cashier station immediately
  • Role-based accounts: cashier accounts only see what a cashier needs at the till, driver accounts only see the deliveries assigned to them
  • Admin accounts sit above both roles, and can sign into either the desktop POS or the web admin panel with the same login
  • Adding, removing, or re-assigning staff roles happens entirely from the admin panel, with no developer needed

Orders, customers, and reporting in one dashboard

The admin panel includes a live dashboard showing customer orders as they move through the system, not a report generated after the fact. The desktop POS, kitchen display, and admin panel all stay in sync over WebSockets, so an order placed at the till appears in the dashboard immediately, with no polling and no separate sync process in between.

Reporting goes beyond a single revenue number. Owners can see total orders, total revenue, average order value, net profit, and expenses for a given period at a glance, then drill into how that revenue breaks down by order type, pickup, delivery, or dine-in, which items are actually selling through a ranked top-items view, and a full order history feed they can scan without exporting anything to a spreadsheet first.

  • Live order tracking, visible the moment an order is placed at any station
  • Sales charts covering revenue over time and order volume
  • Revenue and order breakdown by type, so an owner can see how pickup, delivery, and dine-in actually compare
  • A ranked view of top-selling items, useful for menu decisions as much as for tracking sales
  • Performance reporting across locations and stations, viewable without exporting a spreadsheet

The part most vendors skip: staying on after launch

A POS is infrastructure a restaurant depends on every single day, not a one-time purchase. We still run and maintain this platform today, admin panel included, across every restaurant it is deployed to.

If you are evaluating restaurant POS software, that ongoing piece is worth asking about directly: who is monitoring it once it is live, what can the admin panel actually control versus what needs a support ticket, and what happens the moment the internet drops mid-order. Those questions tend to separate a real POS system from a demo.

The Project

Custom POS software for restaurants: a real-time, offline-first POS system live since June 2026 at Bocconcino Pizza & Donairs in Burlington, Ontario, which we continue to manage.

View Case Study
Watch the Demo

See it in action, then get in touch for more information.

Watch Walkthrough ↗
Related Service

Purpose-built systems for the way your business actually works.

Custom Software Development
Building something similar?

Tell us about your project and we'll follow up with a scoped quote.

Get a Quote

Keep Reading

More from the blog

Pricing Guide

How Much Does Custom Software Development Cost in Canada? (2026 Guide)

Real price ranges for custom software, mobile apps, web apps, POS systems and AI agents in 2026, what drives the cost, and how to keep your budget under control.

Read more →
Restaurant Tech

Custom Restaurant POS vs Square, Toast and Lightspeed: Real Costs for Canadian Restaurants

An honest comparison of off-the-shelf restaurant POS systems and a custom-built POS for Canadian restaurants: costs, fees, offline support and when each one makes sense.

Read more →
App Development

How Long Does It Take to Build an App? Real Timelines from Our Projects

Realistic app development timelines by app type, from MVPs to multi-app platforms, with real delivery times from our projects and what speeds a build up or slows it down.

Read more →

Want to build something like this?

Get a Quote →