
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 image backend for applications and vision pipelines. Upload an image once, then request a WebP preview for your application or a resized raw pixel buffer for your inference worker. Define reusable transformation profiles and manage storage, validation, and deletion through paths that match your application.
10-minute quickstart · Pixels for inference · 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, sharing preprocessing with vision workers, or maintaining several image-handling services. You can run it yourself as a Docker image; there is no SaaS dependency.
A product photo can serve a storefront and a classification worker. Define a profile for each consumer in
konifer.conf:
variant-profiles {
display {
width = 256
height = 256
fit = fill
rotate = auto
format = webp
}
vision {
width = 224
height = 224
fit = fill
rotate = auto
color-space = srgb
format = pixels
pixel-channels = RGB
pixel-layout = planar
}
}Upload the source image, then request each representation:
# Upload the source image
POST /assets/products/123/photo
# Fetch a display image
GET /assets/products/123/photo/-/entry/0/content?profile=display
# Fetch pixels for an inference worker
GET /assets/products/123/photo/-/entry/0/content?profile=visionChoose dimensions, orientation, color space, channel order, and pixel layout in a named profile. Reuse the cached variants across requests, or configure eager generation after upload.
This vision profile produces a 3 × 224 × 224 RGB buffer with one plane per channel. Your worker constructs the
tensor and applies the scaling and normalization required by your model.
See the raw pixel contract for output details and the PyTorch inference guide for a complete worker example, including model-specific preprocessing considerations.
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?width=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 {
width = 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-formats = ["png", "jpg"]
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 accept, reject, or label matching images. The image stays on your server during inference. Install the SigLIP2 model pack to use these rules; see upload rules for the full setup.
The Rule Evaluation API lets you test prompts and
thresholds before enforcing a rule. Enable the API and send a URL or image bytes to POST /rule-evaluations without
storing an asset. The response includes rule matches and per-prompt scores. The scores depend on the image and model;
they are not confidence percentages. The API requires the same 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 image backend for applications and vision pipelines. Upload an image once, then request a WebP preview for your application or a resized raw pixel buffer for your inference worker. Define reusable transformation profiles and manage storage, validation, and deletion through paths that match your application.
10-minute quickstart · Pixels for inference · 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, sharing preprocessing with vision workers, or maintaining several image-handling services. You can run it yourself as a Docker image; there is no SaaS dependency.
A product photo can serve a storefront and a classification worker. Define a profile for each consumer in
konifer.conf:
variant-profiles {
display {
width = 256
height = 256
fit = fill
rotate = auto
format = webp
}
vision {
width = 224
height = 224
fit = fill
rotate = auto
color-space = srgb
format = pixels
pixel-channels = RGB
pixel-layout = planar
}
}Upload the source image, then request each representation:
# Upload the source image
POST /assets/products/123/photo
# Fetch a display image
GET /assets/products/123/photo/-/entry/0/content?profile=display
# Fetch pixels for an inference worker
GET /assets/products/123/photo/-/entry/0/content?profile=visionChoose dimensions, orientation, color space, channel order, and pixel layout in a named profile. Reuse the cached variants across requests, or configure eager generation after upload.
This vision profile produces a 3 × 224 × 224 RGB buffer with one plane per channel. Your worker constructs the
tensor and applies the scaling and normalization required by your model.
See the raw pixel contract for output details and the PyTorch inference guide for a complete worker example, including model-specific preprocessing considerations.
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?width=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 {
width = 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-formats = ["png", "jpg"]
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 accept, reject, or label matching images. The image stays on your server during inference. Install the SigLIP2 model pack to use these rules; see upload rules for the full setup.
The Rule Evaluation API lets you test prompts and
thresholds before enforcing a rule. Enable the API and send a URL or image bytes to POST /rule-evaluations without
storing an asset. The response includes rule matches and per-prompt scores. The scores depend on the image and model;
they are not confidence percentages. The API requires the same 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.