Overview
We have found the Needle in haystack! 🪡🔍
Needle is an open-source image search engine that finds pictures from a description in plain language. It runs as a desktop app on your own machine — no accounts, no cloud, no Docker, and nothing uploaded. Point it at a folder, describe the picture you’re after, and it finds the closest matches.
Born from research on high-accuracy retrieval, Needle outperforms state-of-the-art methods on complex natural-language queries while staying approachable enough to install and use in a couple of minutes. ✨
How it works. Needle doesn’t match your words against text or filenames. It generates a small preview image from your query, embeds it with the same models used to index your library, and retrieves the images that look closest. Comparing images to images is what lets it handle descriptions that tagging and keyword search cannot.
- 🔍 Search in plain language across your own folders.
- 🖥️ Fully local — your photos never leave your machine.
- 🎨 Built-in image generation, on-device and optional.
- 📁 Stays in sync — folders are watched, so new and deleted images are picked up automatically.
- 🍎🐧🪟 macOS, Linux and Windows installers.
See Needle in Action
*Watch as Needle transforms natural language queries into precise image retrieval results in real time.*🎨 Try the Interactive Demo
Experience Needle’s full capabilities with our interactive demo! Test different queries, explore the interface, and see how Needle works with real data.
The demo showcases sample queries, image generation, and similarity search with pre-processed datasets.
Comparison to State-of-the-Art Methods
Curious how Needle measures up against other cutting-edge approaches? Here, you’ll soon find performance plots that compare Needle with OPEN-AI CLIP image retrieval method for LVIS, Caltech256 and BDD100k.
Mean Average Precision Across Datasets (All Queries)
Mean Average Precision Across Datasets (Hard Queries)
User Study Preferences
Get Started Today!
Ready to revolutionize your image retrieval process? 🚀
Install and test Needle now to experience the future of multimodal search!
Tip: For detailed installation instructions, check out the Getting Started section.
Cite us
For a deep dive into Needle’s theoretical guarantees and performance insights, please refer to our research paper.
If you find Needle beneficial for your work, we kindly ask that you cite our work to help support continued innovation.
@article{erfanian2024needle,
title={Needle: A Generative-AI Powered Monte Carlo Method for Answering Complex Natural Language Queries on Multi-modal Data},
author={Erfanian, Mahdi and Dehghankar, Mohsen and Asudeh, Abolfazl},
journal={arXiv preprint arXiv:2412.00639},
year={2024}
}
Getting Started
Prerequisites
Needle is a self-contained desktop application. End users do not need Docker, PostgreSQL, or any external services — everything (metadata via SQLite, vectors via LanceDB, and on-device image generation) runs locally inside the app.
To build Needle from source you need:
- Python 3.12+ — for the bundled backend. Install Python
- Node.js 18+ — for the UI. Install Node.js
- Rust toolchain — for the Tauri desktop shell. Install Rust
Note: Needle is supported on Linux, macOS and Windows.
On macOS, Needle requires macOS 14 (Sonoma) or later on an Apple Silicon Mac. Intel Macs are not supported: PyTorch stopped publishing macOS x86_64 builds after 2.2, so the bundled backend cannot be built for them.
On Windows, Needle requires Windows 10 or later (x64).
Installation
Option A — Download an installer (recommended)
Download the installer for your platform from the releases page:
- macOS:
Needle_x.y.z_macos_arm64.dmg— open it and drag Needle to Applications, then see Opening Needle on macOS below. - Linux:
Needle_x.y.z_linux_amd64.deb(sudo apt install ./Needle_*.deb) orNeedle_x.y.z_linux_x86_64.rpm(sudo dnf install ./Needle_*.rpm). - Windows:
Needle_x.y.z_windows_x64-setup.exe— run it, then see Opening Needle on Windows below.
Each release also ships a .sha256 file so you can verify the download:
shasum -a 256 -c Needle_*_macos_arm64.dmg.sha256
Opening Needle on macOS
The released app is not signed with an Apple Developer ID, because signing and notarization require a paid Apple Developer account. The first time you open it, macOS will refuse and show something like:
“Needle is damaged and can’t be opened. You should move it to the Bin.”
The app is not damaged. That wording is what macOS shows for any app it
cannot attribute to a registered developer. When you download a file, your
browser attaches a com.apple.quarantine flag to it; Gatekeeper checks that
flagged apps are both signed by a known developer and notarized by Apple, and
Needle is neither.
To open it, remove the quarantine flag once:
xattr -dr com.apple.quarantine /Applications/Needle.app
Then launch Needle normally. You only need to do this once per install.
Opening Needle on Windows
The released installer is not code-signed, because a signing certificate is a paid, per-year purchase. Windows SmartScreen therefore blocks it the first time with:
“Windows protected your PC”
Click More info, then Run anyway to continue. The installer places Needle under your user profile, so no administrator prompt is needed.
Some antivirus products also flag freshly built PyInstaller executables as
suspicious. This is a known false positive caused by the way the Python runtime
is bundled; verify the download against the published .sha256 if in doubt, or
build from source.
Why not just right-click → Open? That shortcut no longer works for unsigned apps on recent macOS versions. Removing the quarantine attribute (or approving the app under System Settings → Privacy & Security after a blocked launch attempt) is the supported route.
If you would rather not run that command, build from source instead — apps you build locally are never quarantined, so they open with no extra steps.
Option B — Build & install from source
git clone https://github.com/UIC-InDeXLab/Needle.git
cd Needle
./scripts/build-app.sh
This builds the UI, bundles the backend into the app, and produces an installer
for your platform under ui/src-tauri/target/release/bundle/. Apps you build
yourself are never quarantined, so they open without the warnings above.
Accuracy profiles
Needle can trade speed for accuracy:
- fast (default): 2 lightweight models, quickest indexing and search.
- balanced: 4 models.
- accurate: 6 models, best results but slower and a larger download.
You pick a profile on the welcome screen at first launch, and can change it later — though changing it means re-indexing your library.
First launch
On first launch Needle asks you to pick an accuracy profile, then downloads the
embedding models for it (roughly 3.7 GB for fast) with live progress. Models
are cached in ~/.cache/huggingface, so later launches start immediately.
Once setup finishes, you’re ready to add a folder and search it.
Note: Needle uses your GPU (CUDA) or Apple Silicon (MPS) when available. It is enabled by default, and you can turn it on or off later under Status → Hardware acceleration; switching reloads the models but does not re-download them.
What’s inside
The app runs a local backend on 127.0.0.1:8000 and starts it for you. Nothing
is exposed to the network, and no data leaves your machine.
If you want to script against it, the API is documented at http://127.0.0.1:8000/docs while Needle is running.
Next steps
- Searching Your Images — add a folder and run your first query.
- Image Generation — how Needle turns a query into images, and how to generate images yourself.
- Status & Settings — storage, updates and hardware acceleration.
Searching Your Images
Needle searches your photos the way you’d describe them to a person. Type “snow covered mountain peaks” and you get the closest matches from your own folders — no tags, no filenames, no manual organising.
How it works
Needle does not try to match your words against text. Instead it:
- Generates a small preview image from your query.
- Embeds that preview with the same models used to index your library.
- Retrieves the images whose embeddings sit closest to it.
Because both sides of the comparison are images, the match is based on what things actually look like. That’s why the query image is shown alongside your results — it tells you exactly what Needle went looking for.
Everything runs on your machine. Your photos are never uploaded.
1. Add a folder
Open Library and choose Add folder. Pick any folder of images; Needle indexes it and then keeps watching it for changes.
Indexing shows live progress. Once a folder is indexed, Needle keeps it in sync automatically:
- New images are picked up and indexed.
- Deleted images drop out of your results.
- Renamed or moved images follow their new path.
You can pause a folder with the toggle (it stays indexed but is excluded from searches) or remove it entirely with the trash icon, which also deletes the data Needle stored for it.
By default Needle indexes the files directly inside the folder you pick. Turn on recursive indexing to include subfolders as well.
Supported formats: JPEG, PNG, WebP, BMP, GIF and TIFF.
2. Search
Open Search and describe what you’re looking for.
Needle generates the query image, then ranks your library against it. Results appear as a grid, with the generated preview shown above them.
Click any result to open it full size, where you can step through the set with the arrow keys and download the original.
Tuning a search
The slider icon in the search bar opens the options:
| Option | What it does |
|---|---|
| Results | How many images to return. |
| Images to generate | How many query images to generate. More images broaden the search and can improve recall, at the cost of speed. |
| Generated size | Resolution of the query image. Larger is slower, and rarely changes the ranking much. |
Getting better results
- Describe the picture, not the subject. “a red bus on a cobbled street” works better than “transport”.
- Mention what’s visually distinctive — colours, setting, time of day, composition.
- Try the accurate profile if results feel loose. It uses more embedding models and is noticeably better at fine distinctions, at the cost of indexing and search time. You can switch profiles at any time, but changing them means re-indexing your library.
Requirements
Search needs two things before it will run:
- At least one indexed folder, and
- A generator that is ready — by default the built-in one, once a model has been downloaded. See Image Generation.
If either is missing, the search box is disabled and Needle links you to the page that fixes it.
Image Generation
Needle answers a query by turning your words into images and then finding the closest matches in your library, so generation is part of normal search. The Generate tab exposes the same engine directly, so you can create images yourself.
Built-in generator
Generation runs in-process, on your machine — no companion service, no server to start, and no API key. It uses the GPU (Apple Silicon MPS, or CUDA) when hardware acceleration is enabled.
Model weights are not bundled with the app and are never downloaded behind your back. Pick a model and press Download; Needle shows live progress and the engine only becomes available once the weights are on disk. Until then the built-in generator reads as off, and search will tell you what is missing rather than quietly pulling several gigabytes.
| Model | Download | Steps | Notes |
|---|---|---|---|
| SD-Turbo (default) | 2.6 GB | 1 | Fastest — roughly 0.6 s per 512px image on an M3 Pro |
| SDXL-Turbo | 6.9 GB | 2 | More detail, at 512–1024px |
You only need one. Start with SD-Turbo; add SDXL-Turbo later if you want more detail. Weights live in the shared Hugging Face cache, so other tools on your machine can reuse them (and the Status page reports how much space they take).
Both are step-distilled: they produce an image in 1–4 denoising steps instead of the usual 25–50, which is what makes local generation fast enough to sit inside a search. Smaller non-distilled models exist, but they still need ~25 steps and end up slower despite being smaller.
Needle requests the fp16 weights, which halves the download compared with full-precision files that would only be cast down on load anyway.
Generating images
Search generates query images for you automatically. The Generate tab is there for when you want to create images yourself.
- Prompt — describe the image; press ⌘↵ to run.
- Size — the sizes each model was trained for.
- Steps — more steps is slower and, for turbo models, rarely better.
- Images — generate up to 8 at once; batching is cheaper per image.
- Seed — fix it to reproduce a result, or leave blank for a random one.
Each result shows the time per image and the seed used, and can be saved to a folder of your choice.
Memory
A loaded pipeline holds several GB. On Apple Silicon that memory is shared with the search models and everything else on the machine, and spilling into swap costs far more than reloading does. Needle therefore unloads the generation model after 5 minutes idle and reloads it from the local cache on next use.
If generation ever feels drastically slower than the figures above, check whether the machine is swapping rather than assuming the GPU is at fault.
Cloud providers
OpenAI and Stability AI can be used instead of, or alongside, the built-in engine. Add an API key under Generators → Configure.
Engines are tried top to bottom in the list. With Fallback chain on, a failing engine hands off to the next enabled one; with it off, only the first enabled engine is used. Reorder priority with the arrows next to each engine.
Use Test on any engine to generate a single throwaway image. It confirms the engine works (and warms the model, so your first real search is fast) without committing to a full search.
Cloud providers send your query text to a third party. The built-in generator does not — with it, nothing leaves your machine.
Status & Settings
The Status page is where Needle reports what it is doing, what it is using, and whether there is a newer version.
Health and library
The top of the page confirms the local backend is running, and summarises your library: how many folders are indexed, how many images are tracked and indexed, how many generators are ready, and how many searches you’ve run.
Version and updates
Needle never checks for updates on its own — nothing is sent anywhere unless you ask. Press Check to compare your version against the published releases. If a newer one exists, Needle shows the release notes and a link to download it.
Updating is a normal install of the new package over the old one. Your library, index and settings live outside the app and are left untouched.
Storage
Needle breaks down what it is using on disk:
| Item | What it is |
|---|---|
| Model weights | Embedding and generation models, in the shared Hugging Face cache |
| Search index | The vector index (LanceDB) |
| Metadata | Which files exist and whether they’re indexed (SQLite) |
| Logs | Application logs |
Model weights dominate, and they are shared with any other Hugging Face tool on your machine — so that space is not necessarily Needle’s alone. The index itself is small: a few hundred kilobytes for a hundred images.
Hardware acceleration
Needle uses your GPU when one is available and usable:
- Apple Silicon — the Metal (MPS) backend.
- NVIDIA — CUDA, if you installed a CUDA build.
- Otherwise it runs on the CPU, which works fine but is slower.
Toggle Use GPU to switch. Needle reloads the models onto the new device; weights are already cached, so nothing is re-downloaded.
The published Linux and Windows builds ship a CPU-only PyTorch, so they report no GPU even on a machine that has one. Building from source with
NEEDLE_ACCEL=cudaproduces a CUDA build.
System and profile
The lower cards report the platform, architecture, the device in use, and the Python and PyTorch versions — useful when filing a bug report.
Search profile shows which accuracy profile is active and which embedding models it uses:
| Profile | Models | Trade-off |
|---|---|---|
| fast | 2 | Quickest to index and search |
| balanced | 4 | Middle ground |
| accurate | 6 | Best results, slowest, largest download |
You choose a profile on first launch. Changing it later means re-indexing your library, since the stored vectors belong to the models that produced them.
Where your data lives
| Platform | Location |
|---|---|
| Linux | ~/.local/share/com.needle.app |
| macOS | ~/Library/Application Support/com.needle.app |
| Windows | %APPDATA%\com.needle.app |
Model weights are separate, in the Hugging Face cache (~/.cache/huggingface on
Linux and macOS). Deleting the data directory resets Needle to a first run
without re-downloading models; see Uninstallation.
Command Line
Every Needle package ships needlectl, a command line interface to the same
backend the app uses. It is not a separate product: both read and write the same
settings, so a change made in one shows up in the other.
Use it to script indexing, run searches from a terminal, or drive Needle on a machine you only reach over SSH.
Getting it on PATH
Linux — the .deb and .rpm install it for you.
macOS — it ships inside the app bundle:
sudo ln -sf /Applications/Needle.app/Contents/Resources/bin/needlectl \
/usr/local/bin/needlectl
Windows — add the app’s resources\bin folder to your PATH:
$dir = "$env:LOCALAPPDATA\Needle\resources\bin"
[Environment]::SetEnvironmentVariable(
"Path", "$([Environment]::GetEnvironmentVariable('Path','User'));$dir", "User")
Before you start
needlectl talks to the backend over HTTP, so Needle must be running —
either the desktop app, or a backend you started yourself.
needlectl service status
On a brand new install, run setup once (the same thing the welcome screen does):
needlectl service setup --profile fast
Indexing folders
needlectl directory add ~/Pictures
needlectl directory list
needlectl directory describe 1
needlectl directory disable 1 # keep indexed, exclude from searches
needlectl directory enable 1
needlectl directory remove ~/Pictures
Searching
needlectl query run "snow covered mountain peaks"
needlectl query run "a red bus on a city street" --n 20
needlectl --output json query run "a cat on a windowsill"
Searches use whichever generators are enabled, in the order set under Generators in the app — the CLI does not keep its own copy.
Generators
needlectl generator list # order, state, and why
needlectl generator models # on-device models
needlectl generator download sd-turbo # fetch weights, with progress
needlectl generator test needle-local # one throwaway image
needlectl generator enable needle-local
needlectl generator disable openai
needlectl generator order needle-local openai stability
needlectl generator fallback off # use only the first enabled one
needlectl generator model sdxl-turbo
needlectl generator credentials openai # prompts, never echoed
System
needlectl service info # version, platform, storage, library counts
needlectl service gpu on
needlectl --version
Output formats
Every command takes --output human|json|yaml, so results can be piped:
needlectl --output json query run "a mountain lake" \
| jq -r '.results[]'
Demo
Experience Needle’s capabilities with our interactive demo! The demo showcases the complete Needle workflow: text-to-image generation and similarity search.
🎯 What You’ll See
The demo demonstrates Needle’s core functionality:
- Text Queries: Click on sample queries to see how Needle works
- Image Generation: AI-generated images based on your text prompts
- Similarity Search: Find similar images from a curated dataset
- Real-time Results: See how Needle processes queries and returns results
🚀 Try the Demo
📋 Demo Features
Search Interface
- Sample Queries: Pre-defined queries to test different scenarios
- Generated Images: See AI-generated images for each query
- Similarity Results: Browse through similar images from the dataset
- Performance Metrics: View timing information for each search
Directory Management
- Dataset Overview: See indexed directories and their status
- Indexing Progress: Watch real-time indexing progress
- Directory Details: View file counts, sizes, and metadata
Generator Configuration
- Available Generators: Browse different image generation engines
- Configuration Options: See how generators can be configured
- Service Status: Monitor generator service health
System Status
- Health Monitoring: Check overall system status
- Service Overview: View all running services
- Performance Metrics: See system performance indicators
🔧 Technical Details
The demo is built with:
- Frontend: React with Tailwind CSS
- Data: Pre-processed sample queries and images
- API: Mock API simulating the full Needle backend
- Images: Curated dataset of 1000+ images with embeddings
📁 Demo Structure
demo/
├── src/
│ ├── sample-queries.json # Pre-defined queries and results
│ └── services/
│ └── mockApi.js # Mock API responses
├── public/
│ └── demo-images/ # Sample images
└── scripts/
└── build-sample-queries.py # Script to generate demo data
🎨 Customizing the Demo
You can customize the demo with your own queries and images:
- Add Images: Place your images in
public/demo-images/ - Update Queries: Edit
src/sample-queries.json - Rebuild: Run the build script to update the demo
For detailed customization instructions, see the Demo Customization Guide.
🚀 Getting Started with Needle
After trying the demo, you can:
- Install Needle: Follow our Getting Started guide
- Search your own images: See Searching Your Images
- Configure Services: Set up your own image generation and search pipeline
The demo is updated automatically with each release. For the latest features, make sure you’re viewing the most recent version.
Uninstallation
Quick Uninstall
To uninstall Needle from your system, run:
curl -fsSL https://raw.githubusercontent.com/UIC-InDeXLab/Needle/main/scripts/uninstall.sh | bash
Or if you have the repository cloned:
./scripts/uninstall.sh
What Gets Removed
By default, the uninstallation script removes:
- The Needle desktop app (
/Applications/Needle.appon macOS; the installed package on Linux and Windows)
Your indexed data is kept by default. It lives in:
~/Library/Application Support/com.needle.app— macOS~/.local/share/com.needle.app— Linux%APPDATA%\com.needle.app— Windows~/.cache/huggingface— downloaded model weights (several GB, shared with other Hugging Face tools)
Complete Cleanup
To also remove indexed data, vectors, saved credentials, and Needle’s cached
models, run with --purge:
./scripts/uninstall.sh --purge
Only Needle’s own entries are removed from the HuggingFace cache, since that directory is shared with other tools that may rely on it.
Manual Cleanup
If you prefer to remove things by hand:
# Remove the app
rm -rf /Applications/Needle.app # macOS
sudo apt remove needle # Linux (.deb)
sudo dnf remove needle # Linux (.rpm)
# Remove all user data (optional)
rm -rf ~/Library/Application\ Support/com.needle.app # macOS
rm -rf ~/.local/share/com.needle.app # Linux
# Remove downloaded models (optional, several GB)
rm -rf ~/.cache/huggingface
On Windows, uninstall Needle from Settings → Apps, then optionally delete
%APPDATA%\com.needle.app and %USERPROFILE%\.cache\huggingface.
Deleting only the data directory (and keeping the Hugging Face cache) resets Needle to a first run without re-downloading several gigabytes of models.