# Jellystat's own readme says it is not being updated and will be rebuilt

> A statistics front end for a media server, MIT licensed, shipped as a container image and a development server. The first real paragraph of its readme is a notice that the project is paused for a rewrite, so that is the first thing a reader needs.

**CyferShepard/Jellystat** — Jellystat is a free and open source Statistics App for Jellyfin

- Repository: https://github.com/CyferShepard/Jellystat
- Stars: 2,485 · Forks: 102
- Language: JavaScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/cyfershepard-jellystat

## The readme opens by announcing the project is paused for a rewrite

Most readmes for a project like this open with what it does. This one opens with a status notice, and it is the most important paragraph on the page.

The maintainer writes that a lot of bugs and issues have been piling up, and that since this was one of the first projects they made using Node.js there was a lot they learnt which could have been done better. They have decided to rebuild the project from the ground up on a more modern architecture, which means a new backend language, a new frontend, and possibly a new database provider. Postgres may stay, but they want to see whether something better exists.

Then the sentence that decides whether you should install it: for now, the project is not going to be updated, for a while. The stated exception is that a few fixes may be pushed for major bugs that are easily reproduced.

The banner above it adds that the project is still in development and to expect some weirdness, which is a more cheerful way of saying the same thing.

So the useful reading is that this is a working application in maintenance limbo. Everything in the current feature list works, or is close to working, and there is no roadmap for it beyond a rewrite whose language, front end and database are all still undecided. The wishlist below the feature list is a list of things to do in the version you already have, not in the one being planned.

For an installer, that changes the question from does this work to how much work will migrating away cost me in a year. The answer depends on your data: the backup and restore feature is what makes that question answerable at all.

## A master override account and an all interfaces default

The environment table is the real security surface of this application, and two of its entries deserve attention before you deploy it.

The first is a master override user and password, documented as a recovery route for the case where the username or password chosen during setup has been forgotten, with a note that both must be set for it to work. The example values in the table are the literal words.

That is a sensible feature to have and an awkward one to have in an environment file, because whoever can set the environment can bypass the account you created through the setup wizard. In a container deployment that means the compose file or your orchestration secret, so the override is only as protected as wherever you keep it. Set a real value or set neither.

The second is the listening address, which defaults to every interface rather than to loopback. For a statistics front end that usually sits behind a reverse proxy, that is the behaviour you want, and for a laptop on café wifi it is not. The variable accepts an IPv6 form as well.

The rest of the table is ordinary and mostly required. Four Postgres variables with no defaults, of which the example values are the obvious ones, plus a flag to enable TLS to the database and a second flag controlling whether the database certificate is verified. That second flag defaults to nothing in the table and its example value is to disable verification, which is the combination you want for a database on your own network and not the combination you want for anything else.

There is also a required token secret for signing authentication tokens, with an example value, and a required timezone with a link to the timezone database list. A timezone marked required with no default means the container starts with whatever string you supplied, which is where the compose file's placeholder comes in.

## Three UI frameworks and four Postgres clients in one application

The dependency list is the most informative document in the repository, because it describes what has accumulated rather than what was designed.

There are three separate user interface systems in the front end. A Material Design component library at version six with its own data grid and date picker packages and an accompanying icon set. A second component library in the Bootstrap family, with the base framework and the React bindings both present. And an emotion based styling runtime with two packages. A single React application is loading all three, and each brings its own theming, its own bundle weight and its own conventions.

Then there are four ways to talk to Postgres. A query builder, the bare driver, a promise wrapper over the driver, and a streaming query extension. The streaming one and the builder are complementary in principle; the promise wrapper and the bare driver are alternatives, and using both means two connection pools unless something is shared between them.

Two dependencies are not final releases. The component library's lab package is pinned to a beta of its next major, and the version comparison library is pinned to a release candidate. Both are in a published application whose own version matches its newest release, so a consumer inherits prerelease code by default.

The remainder is a sensible set: an HTTP client, response compression, cross origin headers, a dotenv loader, the web framework, a scheduled job library, an upload middleware, a download helper, a data table wrapper, a memoisation helper, a local cache, and a localisation framework with three separate backends for server, browser and HTTP delivered strings.

The maintainer's own wishlist opens with code optimisations. A dependency graph with three component frameworks and two database layers is what that item looks like from the outside.

## The production image is the development tree with nothing removed

The container file has two stages that use the same base image, and the second one copies everything the first one produced.

The build stage installs dependencies and runs the front end build. The runtime stage then copies the entire build stage directory into itself. Since that directory contains the installed dependency tree, including development dependencies, and since the base image is identical, the production image carries the build tool chain with it.

The dependency install has its own oddity. The two package manifests are copied first, then the cache is force cleaned, then dependencies are installed. Cleaning the cache immediately before installing guarantees that every package is fetched fresh over the network, and the manifests were copied precisely so the install could be cached. The lock file is present in the tree and was copied, which means the reproducible install mode was available and not used.

The runtime stage installs one package, a command line web fetcher, and nothing else. It exists for the health check. The base image also gets upgraded and autoremoved in the same layer, which is defensible for a shipped image and slow for a build.

The entry point is a shell script copied in with an executable bit set, and the health check is defined in the image itself, so the container reports unhealthy without an orchestrator being told to look.

## The two health checks spell the same endpoint differently

The same readiness probe is defined twice, once in the container image and once in the compose file, and the two definitions disagree on the spelling of the path.

The image check fetches an authentication configuration endpoint with every letter lowercased. The compose check fetches the same path with internal capitals. Whether that matters depends on how your application routes, and whether it is case sensitive by default depends on the framework and the platform.

What both probes get right is the choice of endpoint. An authentication configuration check is a good readiness probe for this application, because it answers whether the service is up and whether its setup is complete, without touching the database or requiring credentials.

The compose file does the other two things worth copying. It declares a dependency on the database service gated on that service being healthy, rather than on it having started, which removes the class of failures where the application boots before the database is ready. And the database service has its own probe using the standard client readiness command on a ten second interval.

Two defaults in the compose file are worth changing before you use it. The database credentials are written into the file as literal values and passed to both services, and the timezone variable is set to a placeholder word rather than a real zone name. Neither is dangerous in a local trial; both are wrong in a deployment you intend to keep.

## Two scripts that do the same thing, and two different ports

The package manifest has a duplicate and a port mismatch, both small and both capable of costing an afternoon.

Two of the scripts are byte for byte the same command: one named for starting the application and one with a suffix, both changing into the back end directory and running the server. Nothing distinguishes them in the manifest, so anyone wiring a process manager or a documentation step has to pick one arbitrarily.

The development and production ports differ as well. The client development server is started with a host flag and port 3001, while the application itself serves on 3000 in both the container definition and the exposed port in the compose file. That is a reasonable split for a front end with a hot reloading server talking to an API, and it means a proxy rule written against the development port silently does nothing in production.

Two more details. The manifest's main field points at a JSX file in the source directory, which is a front end entry point rather than a module anything would import, so the field is decorative on a package that is marked private and never published. And the lint configuration treats warnings as errors, with a flag that reports unused disable directives, which is the strictest reasonable setting for a front end codebase and explains why there is a separate lint script rather than a pre-commit hook running the same thing.

The development entry point also starts the server under the debugger with an inspect flag, and a concurrency runner starts both halves at once, so the local loop is one command.

## The feature list and the wishlist describe two different products

Reading the two lists on the readme next to each other is the clearest way to understand where this project is.

The current list has eight items. Session monitoring and logging. Statistics across every library and every user. Watch history. A user overview with activity. Watch statistics as a separate entry, which suggests the per user view and the per title view are distinct screens. Backup and restore of data. Automatic synchronisation of library items. And integration with a statistics plugin on the media server itself, which is the one item that makes this application sit alongside the server's own reporting rather than replace it.

The wishlist underneath has six. A responsive interface. Code optimisations. Security testing. More validations and error handling. Multi-server support. And more to come.

Read together, that is an application that does one job well on a single server, whose known gaps are interface quality on small screens, dependency weight, the absence of a security review, thin error handling, and no support for more than one server at a time. None of those is a reason not to run it; all of them are reasons to know which one you are signing up for.

The release history is steady. A version in April 2026, one in June, and one in September, with the manifest version matching the newest release. That cadence is consistent with the stated intention of pushing only easily reproduced fixes, and it is the number to watch: if it stops, the rewrite has probably started for real.

## Conclusion

This fits someone running a media server who wants watch statistics and session logs today and is prepared to own the deployment. Four things to settle before you install it. That you have read the project update, because the maintainer states the project will not be updated for a while while a rewrite happens, with only easily reproduced bug fixes expected, so anything you build on it may need migrating later. What the environment variables give you, including a master override account and a listening address that defaults to every interface. What the container actually ships, because the production image is built from the full development tree with no pruning. And whether the health check passing means the app is healthy, since both the compose file and the image define one and they spell the same endpoint differently.

## FAQ

### What port number does JellyStat use?

The application serves on port 3000, which is both the exposed port in the compose file and the port declared in the container image. The client development server is started separately on port 3001. The database is reached on its own port, with the compose file using the standard one, and the database container is given a gigabyte of shared memory.

### how to install jellystat docker

The compose file defines two services, the application and a Postgres container, with the application depending on the database being healthy before it starts. Before running it, replace the two hardcoded database credentials and the placeholder timezone value. Note that the maintainer states the project will not be updated for a while while it is rebuilt.

### What does Jellystat do?

It is a statistics application for a Jellyfin media server: session monitoring and logging, statistics across all libraries and users, watch history, a user overview with activity, watch statistics, backup and restore of data, automatic sync of library items, and integration with the media server's own statistics plugin.

### Is Jellystat still being updated?

Not actively, by the maintainer's own statement. The readme announces a decision to rebuild the project on a new backend language, a new front end and possibly a different database, and says that for now the project will not be updated for a while, with a few fixes expected only for major bugs that are easily reproduced. The manifest version matches the most recent release.

### What are the environment variables Jellystat requires?

Four database variables with no defaults, a token secret for signing authentication tokens, and a timezone are marked required. Two more, a master override username and password pair, enable recovery access if the setup credentials are lost and only take effect when both are set. The listening address defaults to every network interface, and there are separate flags for enabling database TLS and for controlling certificate verification.

## Sources

- [CyferShepard/Jellystat on GitHub](https://github.com/CyferShepard/Jellystat)
- [Issues](https://github.com/CyferShepard/Jellystat/issues)
- [License: MIT](https://github.com/CyferShepard/Jellystat/blob/main/LICENSE)
- [README](https://github.com/CyferShepard/Jellystat/blob/main/README.md)
- [Releases](https://github.com/CyferShepard/Jellystat/releases)

---

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