Traccar handles far more devices than its reputation suggests, and it does start to hurt somewhere. This is what the community reports, what the actual pressure points are, and the architectural move that removes the ceiling instead of raising it.
What people actually report
The Traccar forum is the honest source and it is worth reading rather than paraphrasing. Users ask how to optimise the server for a large number of devices with frequent updates, and the community’s own answer is that it can be used in production and handle far more than a couple of hundred devices, with extensions needed for advanced cases.
Separately, people hit permission model limits — a manager user unable to do what a manager needs to do — which is a different kind of ceiling and arrives earlier for anyone with customers rather than vehicles.
Neither is a defect. Both are what happens when a system designed around one fleet is asked to be a platform.
Where the pressure actually is
Four places, in the order they usually bite.
1. Write volume into one relational table
Every position is a row. A thousand devices reporting every 30 seconds is roughly 2,900 positions a minute, 4.1 million a day. In a row-store with indexes maintained on write, that is sustained pressure that grows linearly and never stops.
The symptom is not a crash. It is the positions table becoming the largest object in the database, index maintenance stretching, and vacuum or its equivalent taking longer than the window you have for it.
2. History queries competing with ingest
The same table serves “draw me last month for this vehicle”. A range scan over hundreds of millions of rows in a row-store reads every column of every matching row, including the fifteen you did not ask for. Do that while ingest is writing at full rate and both get slower.
3. The web interface loading everything
The default UI wants the device list and the latest position for every device. At a hundred devices nobody notices. At two thousand it is a query that gets slower every time somebody opens a browser tab, and there is usually more than one tab.
4. The permission model
Traccar’s model is groups and users. It does not have a tenant concept, so isolating one customer from another means discipline rather than a constraint the database enforces. That is the ceiling that matters if you are reselling, and no amount of tuning moves it.
What tuning actually helps
Before any architectural change, the ordinary things:
- Give the JVM real heap. The default is conservative. Devices held in memory plus connection state adds up.
- Tune the database, not the app. Connection pool sized to cores rather than to devices, and the positions table’s indexes reviewed — an unused index on a write-heavy table is pure cost.
- Reduce reporting frequency where it buys nothing. A parked vehicle reporting every 30 seconds is writing rows that say the same thing. Most trackers support movement-based intervals; using them can cut volume by half or more with no loss of useful detail.
- Set a retention policy and enforce it.
DELETE FROM positions WHERE ...on a huge table is itself an outage. Partition by time so old data can be dropped rather than deleted. - Separate the database onto its own host before you scale the application host. The database is almost always the constraint.
That will take you a long way. What it will not do is change the shape of the problem.
The architectural move
At some point the answer stops being “make the same thing faster” and becomes “stop asking one system to do two jobs”.
Traccar is excellent at the first job: terminating device connections, decoding two hundred-odd protocols, and turning bytes into positions. That work is stateless, horizontally scalable, and genuinely hard — nobody should rebuild it.
The second job is different: storing a long position history cheaply, answering analytical questions over it, deriving trips and events, and serving many tenants. It wants a columnar store, not a row store, and a permission model with tenancy in the schema.
Splitting them means Traccar keeps doing what it is good at and forwards decoded positions onward. Its own database stops being the long-term archive and becomes a short buffer, which removes the pressure from points 1, 2 and 3 at once.
What that looks like in practice
Traccar’s position forwarder, four configuration entries:
<entry key='forward.enable'>true</entry>
<entry key='forward.type'>json</entry>
<entry key='forward.url'>https://your-host/api/webhook/traccar</entry>
<entry key='forward.header'>x-webhook-secret: YOUR_SECRET</entry>Positions then land in a columnar store where a position costs about nineteen bytes and a month of history for a vehicle is a range scan over two columns rather than over fifteen. Traccar’s own retention can drop to days, because it is no longer the archive.
One thing to get right, because it fails quietly: Traccar reports speed in knots. Routly’s Traccar provider converts on ingest so a stock instance works unmodified; if you build your own receiver, do the conversion or you will have a fleet that never exceeds 54 km/h and nobody will notice for a month.
When not to bother
If you are running a few hundred devices for one fleet and the interface is fast enough, none of this applies. Tune the database, set retention, and get on with your job. The split is worth doing when one of these is true:
- History queries are visibly slow, or you have stopped keeping history because of it.
- You have customers rather than vehicles and the permission model is being held together by convention.
- Somebody has asked for fuel-loss detection, driver scoring or scheduled reports, and you are looking at building them.
Frequently asked
How many devices can Traccar handle?
More than most people assume, and the honest answer is that it depends on reporting frequency far more than on device count. A thousand devices reporting every five minutes is a tenth of the load of a thousand reporting every thirty seconds.
Will splitting break anything?
No. The forwarder is additive: Traccar keeps working exactly as before and sends a copy onward. You can run both for as long as you like, which is also how you verify the numbers match.
Do I have to use Routly for the second half?
No. The point of this article stands with any columnar store and your own application. Routly is one implementation of the second half, and it exists because we needed it.
Can I keep Traccar’s interface?
Yes, and some operators do — Traccar for the engineers who know it, the second system for customers and reports.
The demo shows what the second half looks like, with no account required.



