{"id":332,"date":"2026-06-21T15:05:24","date_gmt":"2026-06-21T15:05:24","guid":{"rendered":"https:\/\/marcinzygmunt.pl\/blog\/?p=332"},"modified":"2026-06-22T16:15:19","modified_gmt":"2026-06-22T16:15:19","slug":"nats-jetstream-vs-kafka-lightweight-messaging-for-microservices-and-ai-agents","status":"publish","type":"post","link":"https:\/\/marcinzygmunt.pl\/blog\/nats-jetstream-vs-kafka-lightweight-messaging-for-microservices-and-ai-agents\/","title":{"rendered":"NATS JetStream vs Kafka \u2014 lightweight messaging for microservices and AI agents"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Lightweight messaging for microservices and AI agents \u2014 a Kafka alternative, with a working Java demo.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>NATS JetStream<\/strong>&nbsp;is a lightweight persistence layer on top of the&nbsp;<a href=\"https:\/\/nats.io\/\">NATS<\/a>&nbsp;broker \u2014 a&nbsp;<a href=\"https:\/\/kafka.apache.org\/\">Kafka<\/a>&nbsp;alternative that, for many use cases, is simpler and ships with features Kafka doesn&#8217;t give you out of the box. I built a demo in&nbsp;<strong>Java 25 +&nbsp;<a href=\"https:\/\/micronaut.io\/\">Micronaut<\/a><\/strong>: the same code publishes and consumes through both systems, measures latency, and shows JetStream&#8217;s features live. The code is public \u2014&nbsp;<code>docker compose up<\/code>&nbsp;and it runs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below: the JetStream model vs Kafka&#8217;s log,&nbsp;<strong>latency measurements<\/strong>, five runnable scenarios (deduplication, replay, work queue, KV\u2026), and&nbsp;<strong>use cases where NATS fits ideally<\/strong>&nbsp;\u2014 from edge and microservices to task queues and AI-agent communication.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kafka in two sentences (you know it anyway)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kafka is a distributed\u00a0<strong>log<\/strong>\u00a0\u2014 an append-only record split into partitions, read by consumer groups that track their own\u00a0<strong>offset<\/strong>. It shines where you need huge throughput, durability, and a rich ecosystem (Connect, Streams, ksqlDB). Since version 4 it runs natively in\u00a0<strong><a href=\"https:\/\/kafka.apache.org\/documentation\/#kraft\">KRaft<\/a><\/strong>\u00a0mode.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The price of that power is operational complexity and a model where a lot is done&nbsp;<em>around<\/em>&nbsp;the broker: deduplication, task queues, replaying from a specific point. It&#8217;s doable \u2014 just not always elegant.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">NATS and JetStream \u2014 a light core with strong features<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>NATS<\/strong>\u00a0is a lightweight pub\/sub broker: a single binary, sub-second startup, hierarchical subjects (<code>orders.eu.*<\/code>). On its own it delivers\u00a0<em>at-most-once<\/em>\u00a0\u2014 fast, but without durability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>JetStream<\/strong>&nbsp;is a persistence layer built into the same server and the same client. It adds streams, durable consumers, and guarantees \u2014 without standing up separate infrastructure. And this is where it gets interesting, because JetStream has a few things that take gymnastics in Kafka:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Per-message deduplication<\/strong>&nbsp;\u2014 set the&nbsp;<code>Nats-Msg-Id<\/code>&nbsp;header and the server drops repeats within a dedup window. Idempotent publish &#8220;for free&#8221;, durable across client sessions. In Kafka, producer idempotence is limited to a single session.<\/li>\n\n\n\n<li><strong>Client-side replay<\/strong>&nbsp;\u2014 the consumer picks its own start point:&nbsp;<code>DeliverPolicy<\/code>&nbsp;<code>ByStartTime<\/code>&nbsp;(from a moment) or&nbsp;<code>ByStartSequence<\/code>&nbsp;(from a number). Many independent consumers replay the same history&nbsp;<strong>without<\/strong>&nbsp;groups or resetting offsets.<\/li>\n\n\n\n<li><strong>Per-message acknowledgment<\/strong>&nbsp;\u2014&nbsp;<code>ack()<\/code>&nbsp;(at-least-once),&nbsp;<code>ackSync()<\/code>&nbsp;(double-ack, confirmed by the server),&nbsp;<code>nak()<\/code>, redelivery after&nbsp;<code>AckWait<\/code>. Kafka commits a&nbsp;<em>group&#8217;s<\/em>&nbsp;offset, not an individual message.<\/li>\n\n\n\n<li><strong>WorkQueue<\/strong>&nbsp;\u2014 native queue semantics: a message goes to a single consumer and&nbsp;<strong>disappears after it&#8217;s acknowledged<\/strong>. In Kafka you emulate this with partitions and groups.<\/li>\n\n\n\n<li><strong>KV and Object store<\/strong>&nbsp;\u2014 key-value and object stores built on JetStream, in the same client. The Kafka client has no equivalent.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">On top of that comes\u00a0<strong>operational simplicity<\/strong>: one lightweight server (great for edge and leaf-node clusters too), a simple mental model.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"734\" src=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-features-en-1024x734.png\" alt=\"\" class=\"wp-image-334\" srcset=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-features-en-1024x734.png 1024w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-features-en-300x215.png 300w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-features-en-768x550.png 768w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-features-en.png 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Demo: one API, two backends<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To keep the comparison fair, I built an app where the&nbsp;<strong>same code<\/strong>&nbsp;publishes and consumes through both systems. Stack:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Java 25, Micronaut 5<\/strong>, the&nbsp;<code>micronaut-kafka<\/code>&nbsp;and&nbsp;<code>micronaut-nats<\/code>&nbsp;modules<\/li>\n\n\n\n<li>Kafka (KRaft) and NATS with JetStream in&nbsp;<strong>containers<\/strong><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/HdrHistogram\/HdrHistogram\">HdrHistogram<\/a>&nbsp;for latency percentiles<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">At its heart is a shared&nbsp;<code>MessagePublisher<\/code>&nbsp;port with two implementations (Kafka, JetStream) and a shared sink both consumers report to. That makes the feeder and the measurement backend-agnostic \u2014 you switch with&nbsp;<code>DEMO_BACKEND=kafka|jetstream|both<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public interface MessagePublisher {\n    Backend backend();\n    void publish(String id, String payload, long sentAtEpochNanos);       \/\/ synchronous (demo)\n    void publishAsync(String id, String payload, long sentAtEpochNanos);  \/\/ non-blocking (benchmark)\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kafka is handled declaratively (<code>@KafkaClient<\/code>&nbsp;\/&nbsp;<code>@KafkaListener<\/code>), and JetStream via the raw&nbsp;<code>jnats<\/code>&nbsp;client with the newer, simpler API (Simplified Consumer) \u2014 deliberately, because the declarative, reactive client deferred publishing and skewed the measurement.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What you see live<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>.\/gradlew shadowJar\ndocker compose up --build\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<code>feeder<\/code>&nbsp;publishes a batch of messages to Kafka and JetStream, and the&nbsp;<code>consumer<\/code>&nbsp;(a separate container) prints what it received from both \u2014 with latency computed off a shared clock. A round-trip through both systems in a single terminal window.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Latency benchmark<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<code>benchmark<\/code>&nbsp;mode sends at a steady rate with a warm-up phase,&nbsp;<strong>asynchronously<\/strong>&nbsp;(so the sender keeps pace and doesn&#8217;t skew the result), measures latency against the&nbsp;<em>scheduled<\/em>&nbsp;send time (coordinated-omission-aware), and prints percentiles:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose run --rm -e DEMO_MODE=benchmark -e DEMO_BACKEND=jetstream consumer\ndocker compose run --rm -e DEMO_MODE=benchmark -e DEMO_BACKEND=kafka     consumer\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"597\" src=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-chart-en-1024x597.png\" alt=\"\" class=\"wp-image-335\" srcset=\"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-chart-en-1024x597.png 1024w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-chart-en-300x175.png 300w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-chart-en-768x448.png 768w, https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/jetstream-vs-kafka-chart-en.png 1200w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">On a single node, with&nbsp;<strong>equal guarantees<\/strong>&nbsp;(Kafka&nbsp;<code>acks=all<\/code>&nbsp;+ idempotence vs JetStream with a publish ack), at 500 msg\/s,&nbsp;<strong>mean of 3 runs<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>percentile<\/th><th>Kafka<\/th><th>JetStream<\/th><th>JS faster<\/th><\/tr><\/thead><tbody><tr><td>p50<\/td><td>1.85 ms<\/td><td>0.74 ms<\/td><td>2.5\u00d7<\/td><\/tr><tr><td>p95<\/td><td>4.87 ms<\/td><td>1.41 ms<\/td><td>3.5\u00d7<\/td><\/tr><tr><td>p99<\/td><td>10.59 ms<\/td><td>2.94 ms<\/td><td>3.6\u00d7<\/td><\/tr><tr><td>p99.9<\/td><td>19.38 ms<\/td><td>6.61 ms<\/td><td>2.9\u00d7<\/td><\/tr><tr><td>max<\/td><td>21.48 ms<\/td><td>8.49 ms<\/td><td>2.5\u00d7<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">JetStream is faster at&nbsp;<strong>every percentile<\/strong>&nbsp;(~2.5\u20133.6\u00d7), and the&nbsp;<strong>tail<\/strong>&nbsp;is the most telling part: where Kafka blows out at p99.9\/max (~19\u201321 ms), JetStream stays tight (~7\u20138 ms) \u2014 its worst case (max 8.5 ms) beats Kafka&#8217;s p99 (10.6 ms).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two caveats, to be fair: this is&nbsp;<strong>one node<\/strong>&nbsp;(RF=1 \u2014 it doesn&#8217;t show the cost of replication), and the numbers are&nbsp;<strong>illustrative<\/strong>&nbsp;and heavily configuration-dependent. A fun finding from building the demo: when I published&nbsp;<em>synchronously<\/em>, Kafka&#8217;s latency &#8220;jumped&#8221; to tens of milliseconds \u2014 but that was sender backlog, not Kafka&#8217;s fault. After switching to async publishing, everything dropped back to sane values. A common lesson from benchmarks: first you measure your harness, only then the system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The key point:&nbsp;<strong>JetStream&#8217;s real edge isn&#8217;t raw latency \u2014 it&#8217;s the features and the simplicity.<\/strong>&nbsp;And that&#8217;s what the next scenarios show.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">JetStream feature scenarios<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Each one is a self-contained, runnable example that prints an observable effect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose run --rm -e DEMO_MODE=dedup      -e DEMO_BACKEND=jetstream consumer\ndocker compose run --rm -e DEMO_MODE=guarantees -e DEMO_BACKEND=jetstream consumer\ndocker compose run --rm -e DEMO_MODE=replay     -e DEMO_BACKEND=jetstream consumer\ndocker compose run --rm -e DEMO_MODE=workqueue  -e DEMO_BACKEND=jetstream consumer\ndocker compose run --rm -e DEMO_MODE=kv         -e DEMO_BACKEND=jetstream consumer\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>dedup<\/strong>&nbsp;\u2014 two publishes with the same&nbsp;<code>Nats-Msg-Id<\/code>; the second comes back as&nbsp;<code>duplicate=true<\/code>, and the stream keeps&nbsp;<strong>one<\/strong>&nbsp;message.<\/li>\n\n\n\n<li><strong>guarantees<\/strong>&nbsp;\u2014 we receive a message and deliberately don&#8217;t ack it \u2192 after&nbsp;<code>AckWait<\/code>&nbsp;it arrives&nbsp;<strong>again<\/strong>&nbsp;(redelivery); after&nbsp;<code>ackSync<\/code>&nbsp;deliveries stop.<\/li>\n\n\n\n<li><strong>replay<\/strong>&nbsp;\u2014 we publish 5 events, then two independent consumers replay history from the 3rd event: one by sequence, the other by time \u2014 without resetting offsets.<\/li>\n\n\n\n<li><strong>workqueue<\/strong>&nbsp;\u2014 6 jobs, two competing workers; each job handled&nbsp;<strong>exactly once<\/strong>, the queue drains after ack.<\/li>\n\n\n\n<li><strong>kv<\/strong>&nbsp;\u2014 put\/get\/update with revision numbers.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">What it looks like in code<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The best &#8220;for free&#8221; example \u2014 deduplication is a single&nbsp;<code>messageId<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PublishOptions opts = PublishOptions.builder().messageId(\"order-42\").build();\njs.publish(subject, body, opts);\nPublishAck ack = js.publish(subject, body, opts);   \/\/ same Nats-Msg-Id\n\/\/ ack.isDuplicate() == true \u2014 the stream keeps a single message\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And replay is the consumer choosing its start point \u2014 no offset resets:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ConsumerConfiguration.builder().deliverPolicy(ByStartTime).startTime(cutoff).build();\n\/\/ or: .deliverPolicy(ByStartSequence).startSequence(seq)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The rest (guarantees, WorkQueue, KV) is in the repo \u2014 the code is deliberately readable so you can paste it straight into your own project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where JetStream really shines<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">AI agent systems \u2014 the killer use case<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Building a multi-agent system? This is JetStream&#8217;s strongest use case today. Three pillars:&nbsp;<strong>fast messaging<\/strong>&nbsp;between agents (lots of small control messages \u2014 routing, tool calls, status updates), the&nbsp;<strong>WorkQueue<\/strong>&nbsp;pattern (a pool of agents pulls tasks from a queue, each handled exactly once), and&nbsp;<strong>dedup by ID<\/strong>&nbsp;\u2014 an agent can safely retry a command, and&nbsp;<code>Nats-Msg-Id<\/code>&nbsp;guarantees the tool won&#8217;t run the same task twice. All of it under one roof:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>pub\/sub over subjects<\/strong>\u00a0(<code>agent.planner<\/code>.*,\u00a0<code>agent.tools.search<\/code>) \u2014 natural routing of tasks and events between agents,<\/li>\n\n\n\n<li><strong>deduplication<\/strong>&nbsp;\u2014 an agent can safely retry a command;&nbsp;<code>Nats-Msg-Id<\/code>&nbsp;guarantees the tool runs it once (idempotent commands),<\/li>\n\n\n\n<li><strong>per-message ack + redelivery<\/strong>&nbsp;\u2014 a task handed to a worker agent won&#8217;t get lost; if it isn&#8217;t acked, it comes back,<\/li>\n\n\n\n<li><strong>KV store as shared memory\/state<\/strong>&nbsp;\u2014 context, configuration, the agents&#8217; &#8220;scratchpad&#8221;,<\/li>\n\n\n\n<li><strong>replay<\/strong>&nbsp;\u2014 a new (or restarted) agent replays the conversation\/event history from a chosen point to catch up on context,<\/li>\n\n\n\n<li><strong>WorkQueue<\/strong>&nbsp;\u2014 a pool of worker agents pulls tasks from a queue, each handled once.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">And all of this on a&nbsp;<strong>lightweight server<\/strong>&nbsp;that&#8217;s easy to run next to your app \u2014 without pulling in a heavy streaming platform just so agents can talk to each other.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Other good fits<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Edge \/ IoT<\/strong>&nbsp;\u2014 a light broker, leaf nodes, working over flaky connectivity.<\/li>\n\n\n\n<li><strong>Task queues<\/strong>&nbsp;\u2014 native WorkQueue instead of emulating it with partitions.<\/li>\n\n\n\n<li><strong>Event sourcing \/ audit<\/strong>&nbsp;\u2014 replay by time or sequence as a built-in feature.<\/li>\n\n\n\n<li><strong>Microservices without heavy infrastructure<\/strong>&nbsp;\u2014 pub\/sub, request-reply, and KV in one.<\/li>\n\n\n\n<li><strong>Live config and feature flags<\/strong>&nbsp;\u2014 a KV store with change watching.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Summary \u2014 what to pick<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Reach for&nbsp;<strong>Kafka<\/strong>&nbsp;when you need extreme throughput, a rich streaming ecosystem (Connect\/Streams), data-warehouse integrations, and you have a team that already knows it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consider&nbsp;<strong>NATS JetStream<\/strong>&nbsp;when you care about&nbsp;<strong>operational simplicity<\/strong>&nbsp;and need features in the core: deduplication, per-message ack, replay, queues, KV \u2014 or you&#8217;re building something lightweight: agent communication, edge, microservices. It often turns out you get &#8220;for free&#8221; what you&#8217;d have to bolt on in Kafka.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd17&nbsp;<strong>More:<\/strong>&nbsp;<a href=\"https:\/\/nats.io\/\">NATS<\/a>&nbsp;\u00b7&nbsp;<a href=\"https:\/\/docs.nats.io\/nats-concepts\/jetstream\">JetStream docs<\/a>&nbsp;\u00b7&nbsp;<a href=\"https:\/\/github.com\/nats-io\/nats.java\">Java client (jnats)<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Best of all, just run the demo and see the difference for yourself \ud83d\udc47<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd17&nbsp;<strong>Repo:<\/strong><a href=\"https:\/\/github.com\/marcinzygmunt-pl\/jetstream-vs-kafka-demo\" data-type=\"link\" data-id=\"github.com\/marcinzygmunt-pl\/jetstream-vs-kafka-demo\">&nbsp;github.com\/marcinzygmunt-pl\/jetstream-vs-kafka-demo<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lightweight messaging for microservices and AI agents \u2014 a Kafka alternative, with a working Java demo. NATS JetStream&nbsp;is a lightweight persistence layer on top of the&nbsp;NATS&nbsp;broker \u2014 a&nbsp;Kafka&nbsp;alternative\u2026<\/p>\n","protected":false},"author":1,"featured_media":342,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[88,86,87,91,90,15,89,17,85,84],"class_list":["post-332","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-agent-communication","tag-ai-agents","tag-apache-kafka","tag-edge-computing","tag-event-driven-architecture","tag-java","tag-message-broker","tag-microservices","tag-multi-agent-systems","tag-nats-jetstream"],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/06\/title.jpg","_links":{"self":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/332","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/comments?post=332"}],"version-history":[{"count":6,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/332\/revisions"}],"predecessor-version":[{"id":366,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/332\/revisions\/366"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media\/342"}],"wp:attachment":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media?parent=332"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/categories?post=332"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/tags?post=332"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}