# AirTrail: a self-hosted flight history tracker built on SvelteKit

> A TypeScript web app that imports flights from nine sources, plots them on a world map, and stores everything in your own Postgres database.

**johanohly/AirTrail** — A modern, open-source personal flight tracking system

- Repository: https://github.com/johanohly/AirTrail
- Website: http://airtrail.johan.ohly.dk/
- Stars: 1,580 · Forks: 96
- Language: TypeScript
- License: GPL-3.0
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/johanohly-airtrail

## A flight log, not a live position map

The feature list in the README starts with a world map, and it would be easy to read that as a live tracker. It is not. AirTrail is a personal flight history system: you import flights, it stores them, and the map shows the accumulated record. The features confirm the reading, with flight history, statistics, multiple users, responsive design, dark mode and import as the seven bullets.

That distinction matters because it sets expectations about data freshness. There is no ADS-B ingestion in this project and no live aircraft on screen. What you get instead is a searchable archive of trips you have already flown, which is a different and arguably more useful thing once you have a few years of flying behind you.

The project describes itself as a modern open-source personal flight tracking system, is written in TypeScript, and is licensed GPL-3.0. It has 1,580 stars and 96 forks, with 13 open issues, and the repository is not archived. The last push was on 2026-09-03, which is recent enough that this is a project in motion rather than a finished artifact someone left running.

## Nine import sources is the actual feature

The import list is the longest and most concrete thing in the README: MyFlightRadar24, App in the Air, JetLog, TripIt, Flighty, byAir, JetLovers and OpenFlights. Eight named services plus OpenFlights as the open data baseline.

That breadth is not incidental. Anyone who tracks flights accumulates a spread across several apps, because the trackers each capture different things well, and consolidating them by hand is tedious enough that people stop doing it. Supporting nine formats means the merged history is worth something.

The v3.12.0 release notes show what happens after the import: a Miles & More importer was added, mapping was added for unknown airlines and aircraft, and, most usefully, there is field-by-field conflict resolution when AeroDataBox returns different information than what you already had. Silent overwriting of your own records would be a bad default, so conflict resolution at that level of granularity is the right design for an archive you care about.

## Tracks turn a uniform arc into the path actually flown

Flight tracks arrived in v3.11.0 and they change what the map can show. Without a track, a route between two airports is drawn as a smooth arc. With one, the map shows the real path, including taxiing when the data contains it. That is the difference between a decorative map and a record you can read back.

The accepted formats are GPX, KML, FR24 CSV and FlightAware CSV. Accepting CSV from both of the major tracking services matters, because that is where the data usually already is.

v3.12.0 built on it in two directions. Tracks can now be coloured by altitude, with a legend and dashed sections where the path was estimated rather than flown, which is an honest way to distinguish real telemetry from interpolation. The same release added readsb trace JSON import, along with help for choosing the right flight when a trace contains multiple legs. Individual flights also got their own details pane, so selecting a flight from the map, the route view or the list focuses the map on that journey.

## Running it means running Postgres yourself

The repository tree shows the shape of the application: a `prisma/` directory, a `docker/` directory, `src/`, `static/`, `tests/`, and both `svelte.config.js` and `vite.config.ts`. It is a SvelteKit application with Prisma as the database layer, and the `package.json` scripts confirm the tooling, with `vite build`, `vite dev`, and separate commands for unit and end-to-end tests.

The environment example makes the database requirement explicit. `DB_URL` points at a Postgres connection string, and the comments say that if you use the provided docker-compose file you should only change the password, which means the compose setup brings up a database for you. The example also sets `BODY_SIZE_LIMIT=20M` with a comment noting that detailed flight tracks are submitted as part of flight forms, so large track uploads are a real constraint rather than a hypothetical one.

There is also a `UPLOAD_LOCATION` setting for file uploads such as airline icons, with the note that if it is not set, file uploads are disabled. That is a sensible default: the feature turns off rather than silently writing somewhere unexpected.

## A password hash leak fixed in v3.11.0

v3.11.0 shipped on 2026-06-28 and v3.11.1 followed four hours later, which is a fast response to a bad release. The patch notes say plainly that v3.11.0 had a production issue where oversized SvelteKit preload `Link` headers could produce `502 Bad Gateway` responses behind nginx, and the warning to upgrade was placed at the top of the v3.11.0 notes themselves.

The same release carried two security hardening fixes. AirTrail had been exposing user password hashes in page data and in user API responses. The release notes are careful to add the context that matters for judging severity: these were Argon2id hashes rather than plaintext passwords, and they are only useful to someone who can also guess the original password. The fix is still the right fix, because a hash in a page payload is a hash that can end up in a cache or a view-source tab.

Beyond that, v3.11.0 added a globe view instead of a flat map, a time-of-day layer showing where it is currently day and night, and a rain layer. The security posture is worth taking seriously for a self-hosted app with an OAuth provider and multiple users, so the v3.11.0 notes are the place to read before exposing an instance.

## Where the data and the icons come from

The acknowledgements section is unusually thorough, and it documents real dependencies you inherit by running this. Airport data comes from ourairports.com. Country borders come from the European Commission's GISCO distribution, both NUTS level 0 and the country borders GeoJSON, plus Natural Earth's admin 0 countries. Country vocabulary comes from the EU vocabularies service and flags from flagpedia.

Airline icons are based on the Soaring Symbols set by Anh Thang, and the README includes a trademark disclaimer stating that logos are for identification and reference only and remain the property of their respective airlines. The project logo comes from Lucide, with the copyright attribution spelled out including the Cole Bemis and Lucide Contributors portions.

This matters more than a typical credits section because the application ships airline imagery and country flags to end users. If you plan to run a public instance, those attributions travel with it, and the GPL-3.0 licence plus the third-party image licensing are two separate obligations.

## Conclusion

AirTrail sits in a specific and rather narrow place: it is a personal flight log, not a live tracker, and its map is a record of where you have been rather than where a plane is right now. For that job the import coverage is the strongest argument for it, since nine source formats arrive through a Prisma schema and a Postgres database you control. The security work in v3.11.0 is worth reading before you expose an instance, because password hashes were appearing in page data until that release. Start from the quick start in the docs, run it with Docker Compose against your own database, and import one file from your most-used tracker to see whether the field mapping matches what you keep.

## FAQ

### What is AirTrail used for?

It is a self-hosted personal flight log. You import flights from services such as MyFlightRadar24, Flighty, TripIt and OpenFlights, and AirTrail stores them in your own Postgres database, plots them on a world map, and produces statistics. It records flights you have already taken rather than tracking aircraft live.

### Which flight tracking services can AirTrail import from?

The README names MyFlightRadar24, App in the Air, JetLog, TripIt, Flighty, byAir, JetLovers and OpenFlights, and the v3.12.0 notes add a Miles & More importer. Importing FlightAware or FR24 tracks is also supported through the track upload formats.

### Can AirTrail show the actual path a flight took instead of a straight line?

Yes, if you attach a track to the flight. Tracks can be uploaded as GPX, KML, FR24 CSV or FlightAware CSV, and the map then draws the real path including taxiing when the data includes it. v3.12.0 added altitude colouring with dashed sections where the path was estimated.

### What database does AirTrail need?

Postgres, configured through the `DB_URL` environment variable, with Prisma as the database layer. The provided docker-compose file brings up a database for you, so in that case you only need to change the password portion of the URL.

## Sources

- [johanohly/AirTrail on GitHub](https://github.com/johanohly/AirTrail)
- [License: GPL-3.0](https://github.com/johanohly/AirTrail/blob/main/LICENSE)
- [Project website](http://airtrail.johan.ohly.dk/)
- [README](https://github.com/johanohly/AirTrail/blob/main/README.md)
- [Releases](https://github.com/johanohly/AirTrail/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/johanohly-airtrail
