Self-hosted service
besscroft/PicImpact avatar
besscroft/PicImpact

PicImpact: a self-hosted photography portfolio with a WebGL viewer and Postgres behind it

自部署的摄影作品网站,支持多种功能特性。PicImpact,分享你和世界!

1,303 stars212 forksTypeScriptMIT

At a glance

What is it?
PicImpact is a Next.js plus Hono.js gallery you deploy yourself, storing images on S3-compatible storage while PostgreSQL holds the album, tag and EXIF metadata. The interesting parts are the WebGL viewer and the metadata model; the cost is a database, object storage and a set of auth secrets you now own.
Who is it for?
Adopt PicImpact if you already run PostgreSQL and an S3-compatible bucket, want EXIF-driven map views and tag filtering without writing a gallery yourself, and are willing to keep the database and the BETTER_AUTH_* secrets under your own control. Do not adopt it if you want a single static folder of HTML you can drop on any host, or if you need storage backends beyond S3 API, Cloudflare R2 and Open List API.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 74 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem PicImpact solves: a portfolio site that owns its own metadata

Most photographers who want a portfolio either hand a monthly fee to a hosted service or assemble something themselves from a static site generator and a folder of JPEGs. The hosted route hides the EXIF data behind someone else's interface. The static route gives you a page of images and nothing else: no tags, no map, no search, no admin panel. PicImpact sits between those two. It is a self-deployable photography site, built with Next.js and Hono.js, that keeps a real database of your images rather than a directory listing. That database is what makes tag filtering, geotagged map markers and per-image EXIF pages possible. The audience is narrow and specific: someone comfortable running PostgreSQL and an object storage bucket, who wants the gallery to be a real application with an admin backend, and who cares about Live Photos and EXIF coordinates. If you only want to publish twelve images a year, the operational surface here is larger than the problem.

What actually runs: Next.js, Hono.js, Prisma and a WebGL viewer

The stack table in the README is the clearest statement of the architecture. Next.js handles rendering, and the project describes SSR-based hybrid rendering with a state mechanism. Hono.js sits alongside it, which in a Next.js project usually means the API surface is handled by a separate small framework rather than by Next.js route handlers. PostgreSQL is the database, accessed through Prisma, and the README states that Prisma handles automatic database initialization and data migration, which is the part that most self-hosted projects make you do by hand. Authentication is delegated to better-auth, covering email and password, TOTP and WebAuthn. Image rendering is a WebGL viewer based on Afilmory, and the README describes tiling and LOD as the mechanism for large images. That combination tells you where the load sits: the browser does the zooming and panning work on the GPU, the server does not generate resized derivatives on the fly for viewing, and the database holds the relationships. The upload path is the exception. According to the README, batch upload generates a 0.3x compressed image at upload time, so the derivative is produced once and stored, not computed per request. That is a deliberate choice with a cost: it is fast to serve and it doubles the objects in your bucket.

Deployment paths and the environment keys you must set

There are three deployment shapes in the material: Vercel, Node.js, and Docker or Kubernetes. The Vercel path is the one with a button, and it comes with a warning in bold: set the Build Command to pnpm run build:vercel. For a Node.js deployment the README names pnpm run build:node instead. Local development is three commands: git clone the repository, pnpm i, then pnpm run dev. The environment variables are where the real configuration lives. DATABASE_URL is the PostgreSQL connection string, and the README gives a Supabase example using port 6543 with pgbouncer=true. DIRECT_URL exists separately because prisma migrate needs a direct connection; for a non-serverless database the README says it can be identical to DATABASE_URL. BETTER_AUTH_SECRET is generated with npx auth secret. BETTER_AUTH_URL is your public address. BETTER_AUTH_PASSKEY_RP_ID is your domain, and BETTER_AUTH_PASSKEY_RP_NAME is a display name such as PicImpact. One constraint is stated plainly: Passkey depends on an HTTPS environment, with localhost allowed for local development. If you terminate TLS somewhere that does not present the right origin to the browser, WebAuthn will not work, and the README does not describe a workaround.

Storage backends and the metadata that only exists if uploads go through the app

PicImpact lists three storage options: S3 API, Cloudflare R2, and Open List API. That is a compatibility claim, not a description of behaviour. The README does not say whether all three support every feature, and it does not describe how credentials are configured per backend beyond the existence of a storage configuration screen in the admin dashboard. Treat that as the first thing to verify on your own infrastructure. The metadata story has a similar shape. EXIF information, map coordinates and tags are all presented as per-image data, which means they must be captured when the image enters the system. The README describes batch automated upload as the path that generates the 0.3x preview, so images added by that route get both the derivative and, presumably, the metadata extraction. Images that arrive some other way, or that are moved into the bucket directly, are not covered by any statement in the material. If you point PicImpact at a bucket that already contains years of photos, you should not assume the map view and EXIF pages will populate. The README does not document an import or backfill command.

Authentication is heavier than most galleries need

The auth feature list is longer than the gallery feature list in places. Email and password, TOTP per RFC 6238 with Google Authenticator, Microsoft Authenticator and 1Password named as compatible clients, and Passkey via WebAuthn with biometrics and hardware keys. This is better-auth doing the work, and it is a genuine advantage over the typical self-hosted gallery that ships a single admin password in an environment variable. It is also a configuration burden. You are now responsible for BETTER_AUTH_SECRET, for the relying party ID matching your domain, and for HTTPS being present, because Passkey will not function without it. The failure mode is quiet: passkeys simply will not register, and you fall back to a password without understanding why. There is no statement in the README about what happens to existing sessions when BETTER_AUTH_SECRET changes, so rotate it deliberately and expect to re-authenticate.

Where PicImpact is the wrong tool

The clearest case against it is a static gallery. If your images are already processed, you do not need per-image database rows, and you do not want to run PostgreSQL to display them. A static site generator that reads EXIF at build time will give you a folder of HTML you can host anywhere, with no secrets and no migration step. The second case is a shared or multi-user photo platform. PicImpact is described as a photography portfolio, with an admin dashboard for statistics, upload, image management, album management, settings and storage configuration. That is a single-operator model. Nothing in the README describes per-user accounts, quotas, or upload permissions for anyone other than the administrator. The third case is storage you cannot move. If your images live in a backend outside S3 API, Cloudflare R2 and Open List API, the README offers no adapter path. Finally, the documentation itself is a constraint. The homepage points to pic-docs.besscroft.com, but the English README points to pic-docs.ziyume.com, and the two do not match. That inconsistency is worth resolving before you plan a deployment around either URL.

Release cadence and what it costs you to stay current

The release list shows v3.3.5, v3.3.6 and v3.3.7 within days of each other in June 2026, and the last push to the repository is dated 2026-07-03. The README's own advice is conservative: it recommends updating only when a new version is released. That is a mild contradiction with the cadence, since three patch releases in three days means the release event is frequent. The practical cost is migration. Prisma handles database initialization and migration automatically, which lowers the effort, but automatic migration also means an upgrade can alter your schema without you reviewing the SQL first. If that matters to you, run the migration against a copy of the database before pointing it at production. The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are preserved. That is the standard permissive arrangement and it does not obligate you to publish your own changes. This is a description of the licence text, not legal advice; if you are embedding PicImpact in a product, read the LICENSE file in the repository yourself.

Editorial conclusion

Adopt PicImpact if you already run PostgreSQL and an S3-compatible bucket, want EXIF-driven map views and tag filtering without writing a gallery yourself, and are willing to keep the database and the BETTER_AUTH_* secrets under your own control. Do not adopt it if you want a single static folder of HTML you can drop on any host, or if you need storage backends beyond S3 API, Cloudflare R2 and Open List API. Before committing, verify three things against your own setup: that DIRECT_URL reaches your PostgreSQL instance for prisma migrate, that the domain you put in BETTER_AUTH_PASSKEY_RP_ID is served over HTTPS, and that your chosen storage backend can serve full-resolution originals for direct link access, since the README does not state which of the three backends support which operations.

Official sources

  1. besscroft/PicImpact on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes