
Self-hosted image backend handling uploads, validation, S3/filesystem storage, libvips-powered transformations, SigLIP2 content classification, path-based rules and variants, plus CDN-friendly redirect delivery.
Konifer is a self-hosted backend for images your application owns. It handles uploads, validation, storage, transformations, and deletion. Name assets the way your application already thinks about them, then give each path its own rules.
10-minute quickstart · Documentation · Performance report
Konifer handles the image lifecycle. Put a CDN in front of it for delivery. If all you need is on-demand resizing, imgproxy or whatever your CDN offers may be a better fit.
I've seen the same story on several teams: someone needs to store a product photo, then another feature needs thumbnails, then a third needs different upload limits. Before long, image handling is spread across S3 buckets, Lambdas, queues, and services. Konifer puts those jobs behind one API while letting each part of your application keep its own rules.
It supports:
Konifer is worth a look if you're adding images to an application, maintaining several image-handling services, or spending more engineering time on image plumbing than the feature that needed the images in the first place. You can run it yourself as a Docker image; there is no SaaS dependency.
You can use a path that already means something to your application:
POST /assets/users/123/profile-picture
GET /assets/users/123/profile-picture/-/redirect?profile=thumbnail
GET /assets/users/123/profile-picture/-/infoAn opaque ID works too:
POST /assets/0d79ddf9-8bbb-42a1-9435-9c166ca4dfb6
GET /assets/0d79ddf9-8bbb-42a1-9435-9c166ca4dfb6/-/redirect?w=256&format=webpPaths give you a way to work with related assets. If user 123 closes their account, you can delete the assets below
users/123 with one request:
POST /assets/users/123/profile-picture
POST /assets/users/123/article/456
POST /assets/users/123/article/789
DELETE /assets/users/123/-/recursiveThe same paths can choose how Konifer treats each image. This example gives every user image a pixel limit, creates a thumbnail for profile pictures, and leaves article resizing to the CDN:
variant-profiles {
thumbnail {
w = 256
fit = fill
}
}
paths {
"/users/**" {
limits {
max-pixels = 15MP
}
}
"/users/*/profile-picture" {
object-store {
bucket = profiles
}
transform {
eager-variants = [thumbnail]
on-demand-variant {
mode = profile_only
}
}
}
"/users/*/article/**" {
object-store {
bucket = articles
}
allowed-content-types = ["image/png", "image/jpeg"]
transform {
on-demand-variant {
mode = disabled
}
}
}
}Path rules inherit from broader matches, so both specific paths get the /users/** pixel limit. The
path configuration docs cover matching and inheritance.
Some uploads need a content check as well as a file type check. Konifer can compare an image with a collection of prompts using SigLIP2 in the server process. For example:
rule-definitions {
"blood-and-gore" {
prompts = [
"graphic visible blood",
"open wound with blood",
"bloody injury scene",
"gore and severe injury"
]
threshold = 0.72
}
}You can attach a definition to a path's upload ruleset to reject or label matching images. The image stays on your server during inference. See upload rules for the full setup.
The Rule Evaluation API lets you test prompts and
thresholds before enforcing a rule. Send a URL or image bytes to POST /rule-evaluations without storing an asset. The
response shows which prompts drove the score:
{
"results": [
{
"name": "outdoor-landscape",
"threshold": 0.7,
"score": 0.83,
"matched": true,
"promptScores": [
{ "prompt": "a mountain", "score": 0.83 },
{ "prompt": "a forest", "score": 0.41 }
]
}
]
}Those numbers illustrate the response shape. The scores depend on the image and model; they are not confidence percentages. The docs cover enabling the API and installing the model pack.
Start with the quickstart, then see the asset model, image transformation reference, and storage configuration. The full documentation also covers caching, URL signing, and deployment.
The interactive performance report tracks latency across releases and mixed workloads. Its current runs use a laptop; AWS hardware testing is planned.
Konifer ships as a Docker image. For local development, install the native dependencies and download the SigLIP2 model pack if you work on inference or its tests. CONTRIBUTING.md has the setup steps, Gradle tasks, and macOS notes.
A huge thank-you to these open-source projects:
Questions or feedback? Email me at daniel@konifer.io or start a discussion on GitHub.
The Konifer server is released under the AGPL license in LICENSE.
The Konifer client and common module are licensed under Apache 2.0 license in LICENSE and LICENSE, respectively.
Konifer is a self-hosted backend for images your application owns. It handles uploads, validation, storage, transformations, and deletion. Name assets the way your application already thinks about them, then give each path its own rules.
10-minute quickstart · Documentation · Performance report
Konifer handles the image lifecycle. Put a CDN in front of it for delivery. If all you need is on-demand resizing, imgproxy or whatever your CDN offers may be a better fit.
I've seen the same story on several teams: someone needs to store a product photo, then another feature needs thumbnails, then a third needs different upload limits. Before long, image handling is spread across S3 buckets, Lambdas, queues, and services. Konifer puts those jobs behind one API while letting each part of your application keep its own rules.
It supports:
Konifer is worth a look if you're adding images to an application, maintaining several image-handling services, or spending more engineering time on image plumbing than the feature that needed the images in the first place. You can run it yourself as a Docker image; there is no SaaS dependency.
You can use a path that already means something to your application:
POST /assets/users/123/profile-picture
GET /assets/users/123/profile-picture/-/redirect?profile=thumbnail
GET /assets/users/123/profile-picture/-/infoAn opaque ID works too:
POST /assets/0d79ddf9-8bbb-42a1-9435-9c166ca4dfb6
GET /assets/0d79ddf9-8bbb-42a1-9435-9c166ca4dfb6/-/redirect?w=256&format=webpPaths give you a way to work with related assets. If user 123 closes their account, you can delete the assets below
users/123 with one request:
POST /assets/users/123/profile-picture
POST /assets/users/123/article/456
POST /assets/users/123/article/789
DELETE /assets/users/123/-/recursiveThe same paths can choose how Konifer treats each image. This example gives every user image a pixel limit, creates a thumbnail for profile pictures, and leaves article resizing to the CDN:
variant-profiles {
thumbnail {
w = 256
fit = fill
}
}
paths {
"/users/**" {
limits {
max-pixels = 15MP
}
}
"/users/*/profile-picture" {
object-store {
bucket = profiles
}
transform {
eager-variants = [thumbnail]
on-demand-variant {
mode = profile_only
}
}
}
"/users/*/article/**" {
object-store {
bucket = articles
}
allowed-content-types = ["image/png", "image/jpeg"]
transform {
on-demand-variant {
mode = disabled
}
}
}
}Path rules inherit from broader matches, so both specific paths get the /users/** pixel limit. The
path configuration docs cover matching and inheritance.
Some uploads need a content check as well as a file type check. Konifer can compare an image with a collection of prompts using SigLIP2 in the server process. For example:
rule-definitions {
"blood-and-gore" {
prompts = [
"graphic visible blood",
"open wound with blood",
"bloody injury scene",
"gore and severe injury"
]
threshold = 0.72
}
}You can attach a definition to a path's upload ruleset to reject or label matching images. The image stays on your server during inference. See upload rules for the full setup.
The Rule Evaluation API lets you test prompts and
thresholds before enforcing a rule. Send a URL or image bytes to POST /rule-evaluations without storing an asset. The
response shows which prompts drove the score:
{
"results": [
{
"name": "outdoor-landscape",
"threshold": 0.7,
"score": 0.83,
"matched": true,
"promptScores": [
{ "prompt": "a mountain", "score": 0.83 },
{ "prompt": "a forest", "score": 0.41 }
]
}
]
}Those numbers illustrate the response shape. The scores depend on the image and model; they are not confidence percentages. The docs cover enabling the API and installing the model pack.
Start with the quickstart, then see the asset model, image transformation reference, and storage configuration. The full documentation also covers caching, URL signing, and deployment.
The interactive performance report tracks latency across releases and mixed workloads. Its current runs use a laptop; AWS hardware testing is planned.
Konifer ships as a Docker image. For local development, install the native dependencies and download the SigLIP2 model pack if you work on inference or its tests. CONTRIBUTING.md has the setup steps, Gradle tasks, and macOS notes.
A huge thank-you to these open-source projects:
Questions or feedback? Email me at daniel@konifer.io or start a discussion on GitHub.
The Konifer server is released under the AGPL license in LICENSE.
The Konifer client and common module are licensed under Apache 2.0 license in LICENSE and LICENSE, respectively.