Every time you send data to an LLM, you pay per token. And most of that data is structured: JSON responses from APIs, CSV exports from databases, YAML config files, XML payloads from legacy systems. The problem is that none of these formats were designed with LLMs in mind. They were designed for humans and machines to read. The result is that you end up sending thousands of tokens worth of brackets, colons, quotes, and whitespace that carry almost zero actual information.
PackLM was built to fix exactly that.
When developers think about reducing LLM costs, they usually think about shortening their prompts or switching to a cheaper model. But there is a third option that almost nobody considers: compressing the data you send before it ever reaches the model.
Take a simple product list:
[
{ "name": "Wireless Keyboard", "price": 29.99, "stock": 45 },
{ "name": "USB Hub", "price": 14.49, "stock": 120 },
{ "name": "Monitor Stand", "price": 34.0, "stock": 8 }
]Every row repeats the same keys. Every string sits inside quotes. Every value is fenced by colons and commas. By the time you have 50 products, a significant chunk of your token budget has gone toward structural noise rather than actual data.
This is not a corner case. It is the default state of how developers send data to LLMs today.
PackLM is an open-source token-efficient structured data format designed for LLM communication. The core idea is straightforward: define the schema once at the top, and let the data rows carry only the values. No repeated keys. No surrounding punctuation. No noise.
Here is the same product list encoded in PackLM:
@R name price stock
R "Wireless Keyboard" 29.99 45
R "USB Hub" 14.49 120
R "Monitor Stand" 34.0 8
@R declares the schema once. Every line starting with R is a data row whose values map directly to those fields in order. The LLM still understands it perfectly because the structure is explicit. But the token count drops from 78 to 25, a saving of 67.9%.
PackLM does not apply one-size-fits-all compression. It reads the shape of your data and picks the most token-efficient encoding strategy for each part of it.
This is the most common case. When you have an array of objects, PackLM defines the schema once and rows follow directly:
@R name price stock
R "Wireless Keyboard" 29.99 45
R "USB Hub" 14.49 120
When your data has a top-level configuration or context object (not a list, just a single dict), PackLM encodes it as a META block. The schema and values sit on two lines rather than being spread across multiple nested levels:
Original JSON:
{
"context": {
"task": "Our favorite hikes together",
"location": "Boulder",
"season": "spring_2025"
}
}PackLM:
# meta:context
@CO task location season
CO "Our favorite hikes together" Boulder spring_2025
One comment line marks it as metadata. One schema line. One data line. Done.
When your data contains a flat array of primitive values like strings or numbers, PackLM skips the schema entirely and writes it as a single space-separated line:
Original JSON:
{ "friends": ["ana", "luis", "sam"] }PackLM:
@friends ana luis sam
That entire array is now one line. The lowercase @ signals to the decoder that this is an inline list, not a schema definition.
When objects contain nested dicts or short primitive arrays inside rows, PackLM handles both without creating separate blocks. Nested dicts get dot-separated field names in the schema. Primitive arrays inside rows become pipe-separated values in a single cell:
Original JSON:
[
{
"id": 1,
"name": "Vivek",
"address": { "city": "Delhi", "zip": "110001" },
"skills": ["Python", "React", "Node"]
},
{
"id": 2,
"name": "Priya",
"address": { "city": "Mumbai", "zip": "400001" },
"skills": ["Go", "Vue"]
}
]PackLM:
@R id name address.city address.zip skills
R 1 Vivek Delhi 110001 Python|React|Node
R 2 Priya Mumbai 400001 Go|Vue
address.city and address.zip are flattened from the nested dict. The skills array collapses into Python|React|Node inside a single cell. The token savings here are 85.4%.
Not all data is flat. Sometimes you have orders with line items, users with transaction histories, or posts with comments. PackLM handles this through child tables that link back to parent rows using a _ref index:
Original JSON:
[
{
"orderId": "A01", "customer": "Alice",
"items": [
{ "product": "Keyboard", "qty": 1, "price": 29.99 },
{ "product": "Mouse", "qty": 2, "price": 12.50 }
]
},
{
"orderId": "A02", "customer": "Bob",
"items": [
{ "product": "Monitor", "qty": 1, "price": 199.0 }
]
}
]PackLM:
@R orderId customer
R A01 Alice
R A02 Bob
# child:items
@IT _ref product qty price
IT 0 Keyboard 1 29.99
IT 0 Mouse 2 12.5
IT 1 Monitor 1 199.0
The # child:items comment marks the child block. The _ref column links each item back to its parent row by index. Alice (row 0) gets two items. Bob (row 1) gets one. The structure is fully preserved with a 75.6% token reduction.
Here is what PackLM looks like when all four strategies fire on the same piece of data:
Original JSON (202 tokens):
{
"context": {
"task": "Our favorite hikes together",
"location": "Boulder",
"season": "spring_2025"
},
"friends": ["ana", "luis", "sam"],
"hikes": [
{ "id": 1, "name": "Blue Lake Trail", "distanceKm": 7.5, "elevationGain": 320, "companion": "ana", "wasSunny": true },
{ "id": 2, "name": "Ridge Overlook", "distanceKm": 9.2, "elevationGain": 540, "companion": "luis", "wasSunny": false },
{ "id": 3, "name": "Wildflower Loop", "distanceKm": 5.1, "elevationGain": 180, "companion": "sam", "wasSunny": true }
]
}PackLM (60 tokens — 70.3% smaller):
# meta:context
@CO task location season
CO "Our favorite hikes together" Boulder spring_2025
@friends ana luis sam
# hikes
@HI id name distanceKm elevationGain companion wasSunny
HI 1 "Blue Lake Trail" 7.5 320 ana True
HI 2 "Ridge Overlook" 9.2 540 luis False
HI 3 "Wildflower Loop" 5.1 180 sam True
The context dict becomes a META block. The friends array becomes a single inline line. The hikes list becomes a clean table. Everything is lossless and reversible back to the original JSON.
PackLM v2 addressed two concrete issues that surfaced from real usage.
The first was token estimation accuracy. Earlier estimates used rough approximations that did not account for how tokenizers handle special characters and punctuation. v2 switched to a more precise counting method that reflects what models actually see, making the cost savings calculator genuinely reliable rather than just directionally correct.
The second was format inefficiencies in edge cases. Certain data shapes, particularly nested JSON and multi-level YAML, were not being compressed as aggressively as possible. v2 introduced smarter flattening logic for these cases and ensures positive token savings across every supported format without exception.
PackLM currently supports conversion from and to all six of the most common structured formats used in developer workflows:
Every one of these formats produces measurably smaller output when converted to PackLM before being sent to an LLM.
PackLM slots into your existing workflow with almost no friction.
Step 1: Paste your data. Open the PackLM converter in your browser. Paste in your JSON, CSV, YAML, XML, TOML, or TSV. No installation. No account. No API key.
Step 2: Convert to PackLM. Hit convert. The encoder parses your data, picks the right strategy for each section, and outputs the PackLM representation. You can see both formats side by side and verify nothing was lost.
Step 3: Check your savings. The real-time cost calculator shows you exactly how many tokens you saved and what that translates to in dollars across different LLM providers.
Step 4: Drop it into your prompt. Copy the PackLM output and use it in your prompt. Models understand the format without extra instructions because the structure is self-describing.
Step 5: Convert back if needed. PackLM supports full round-trip conversion. Run the packed output back through the decoder and you get standard JSON on the other side, identical to what you started with.
LLM pricing keeps falling. But the volume of data being sent to these models is growing faster than prices drop. Agentic workflows, RAG pipelines, automated document analysis, and structured data extraction are all pushing more data into context windows than ever before.
Token efficiency is not a niche optimization. It is becoming a core engineering consideration for anyone building production LLM applications.
PackLM is a concrete piece of that puzzle. It does not require you to change your stack, switch providers, or rewrite your application logic. You pass your data through it, get a leaner version back, and your costs go down.
Try it at packlm.vercel.app — the converter, format spec, library code, and cost calculator are all there in one place. If you want to dig into the source, contribute, or open an issue, the full project is on GitHub at vivekisadev/packlm.
PackLM is open source. Contributions, feedback, and format proposals are welcome on GitHub.