You need search in your app. Elasticsearch wants 2GB of RAM minimum. Your $5/mo VPS has 1GB total. You could use a managed service at $50/mo, or you could use Sonic — a search backend that runs in 10MB of RAM and indexes documents 10x faster than Elasticsearch.
What Sonic Actually Does
Sonic is a fast, lightweight, schema-less search backend written in Rust. It's not a full search engine like Elasticsearch — it's a search index that you pair with your existing database. You push text into Sonic, and it builds an optimized search index. When users search, Sonic returns matching document IDs in microseconds. You fetch the full documents from your database.
This architecture is intentional: Sonic does one thing (search indexing) extremely well instead of trying to be a database, analytics engine, and search engine all at once. The result is a binary under 5MB that handles millions of documents.
Sonic uses a custom channel protocol over TCP (not HTTP/REST), with client libraries available for Node.js, Python, Go, Ruby, Java, PHP, and Rust.
Quick Start
Run Sonic:
docker run -d -p 1491:1491 valeriansaliou/sonic:latest
Using the Node.js client:
const Sonic = require('sonic-channel');
// Ingest channel — push data
const ingest = new Sonic.Ingest({
host: 'localhost', port: 1491, auth: 'SecretPassword'
}).connect();
await ingest.push('articles', 'blog', 'article-1',
'How to build a REST API with Node.js and Express');
await ingest.push('articles', 'blog', 'article-2',
'Building real-time apps with WebSockets and Redis');
await ingest.push('articles', 'blog', 'article-3',
'GraphQL vs REST: choosing the right API paradigm');
// Search channel — query data
const search = new Sonic.Search({
host: 'localhost', port: 1491, auth: 'SecretPassword'
}).connect();
const results = await search.query('articles', 'blog', 'REST API');
console.log(results); // ['article-1', 'article-3']
Using Python:
from sonic import IngestClient, SearchClient
with IngestClient('localhost', 1491, 'SecretPassword') as ingest:
ingest.push('products', 'store', 'sku-100',
'Wireless Bluetooth Headphones Noise Cancelling')
with SearchClient('localhost', 1491, 'SecretPassword') as search:
results = search.query('products', 'store', 'wireless headphones')
print(results) # ['sku-100']
3 Practical Use Cases
1. Add Search to Any Database
// Sync your database to Sonic on write
app.post('/articles', async (req, res) => {
const article = await db.articles.create(req.body);
await ingestChannel.push('articles', 'main',
article.id.toString(), article.title + ' ' + article.body);
res.json(article);
});
// Search endpoint
app.get('/search', async (req, res) => {
const ids = await searchChannel.query('articles', 'main', req.query.q);
const articles = await db.articles.findByIds(ids.map(Number));
res.json(articles);
});
2. Auto-Complete / Suggest
const suggestions = await search.suggest('articles', 'main', 'jav');
// ['javascript', 'java']
Built-in suggestion support — no extra configuration.
3. Multi-Tenant Search
Sonic's collection/bucket architecture supports multi-tenancy natively:
// Each tenant gets their own bucket
await ingest.push('documents', 'tenant-acme', 'doc-1', 'Q1 Report');
await ingest.push('documents', 'tenant-globex', 'doc-1', 'Budget Plan');
// Search is automatically scoped
const acmeResults = await search.query('documents', 'tenant-acme', 'report');
// Only returns Acme's documents
Why This Matters
Not every app needs Elasticsearch. Most apps need fast text search on a few million documents. Sonic gives you that in 10MB of RAM with zero configuration complexity. For indie developers, small teams, and resource-constrained environments, Sonic is the pragmatic choice.
Need custom data extraction or web scraping solutions? I build production-grade scrapers and data pipelines. Check out my Apify actors or email me at spinov001@gmail.com for custom projects.
Follow me for more free API discoveries every week!
Top comments (0)