<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>InfluxData Blog - Developer</title>
    <description>Posts from the Developer category on the InfluxData Blog</description>
    <link>https://www.influxdata.com/blog/category/tech/</link>
    <language>en-us</language>
    <lastBuildDate>Thu, 25 Jun 2026 08:00:00 +0000</lastBuildDate>
    <pubDate>Thu, 25 Jun 2026 08:00:00 +0000</pubDate>
    <ttl>1800</ttl>
    <item>
      <title>How Mumu Migrated From Prometheus to InfluxDB and Tripled Their Metric Coverage</title>
      <description>&lt;p&gt;When a team uses an internal Slack channel for everything from contact form submissions to deployment alerts and server warnings, the notification engine quickly becomes critical infrastructure. When the same team builds that engine as a product for other teams to use, the bar gets even higher.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://usemumu.com/"&gt;Mumu&lt;/a&gt; is an all-in-one productivity platform for modern teams. While most companies stitch together separate SaaS tools for org charts, agile estimation, internal Q&amp;amp;A, skill mapping, recognition, and notifications, Mumu offers all of those as connected modules under a single subscription. The premise is that your organizational structure shouldn’t be replicated across five different databases; it should live in one place and flow into every workflow your team uses.&lt;/p&gt;

&lt;p&gt;In this blog, we will go over why the Mumu team rebuilt their monitoring stack on &lt;a href="https://www.influxdata.com/products/influxdb/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=core-ai-user-mumu&amp;amp;utm_content=blog"&gt;InfluxDB 3&lt;/a&gt; and how the migration went.&lt;/p&gt;

&lt;h2 id="why-pull-based-monitoring-stopped-making-sense"&gt;Why pull-based monitoring stopped making sense&lt;/h2&gt;

&lt;p&gt;Like many teams running their own infrastructure, Mumu started off using Prometheus as its primary monitoring solution. The main problem over time was the fundamental mismatch between Prometheus’s pull-based data collection model and the type of data Mumu was working with. Rather than telemetry data that can be scraped at a regular interval, Mumu often needs to track discrete events like user triggered actions, scripts completing, and a pipeline finishing. As a result, push-based delivery for tracking events made more sense.&lt;/p&gt;

&lt;p&gt;That architectural mismatch wasn’t the only problem. As Mumu evaluated alternatives like Betterstack, VictoriaMetrics, PostHog, Graphite, Datadog, and New Relic, issues related to transparency became a concern. Several of the SaaS solutions came with documentation that made it genuinely hard to understand what was happening under the hood, particularly around how metrics were ingested and stored. For a team that ships fast and needs to be able to debug its own pipeline, that was a dealbreaker.&lt;/p&gt;

&lt;h2 id="why-influxdb-3-was-the-right-option"&gt;Why InfluxDB 3 was the right option&lt;/h2&gt;

&lt;p&gt;Two things about InfluxDB stood out during evaluation. The first was that self-hosting was effortless. Mumu runs its own dedicated servers, and spinning up an InfluxDB 3 Core instance using the official Docker image took almost no time or configuration overhead.&lt;/p&gt;

&lt;p&gt;The second factor was the push-based HTTP API. &lt;a href="https://docs.influxdata.com/influxdb3/core/api/"&gt;InfluxDB’s Line Protocol HTTP API&lt;/a&gt; lets Mumu’s services emit metrics at the exact line of code where an event occurred with no sidecar, no exposition format, no scrape interval, just a POST request at the moment an event happened.&lt;/p&gt;

&lt;p&gt;In hindsight, the team’s biggest evaluation lesson was that they should have built a small proof of concept with InfluxDB earlier. The time spent evaluating other tools wasn’t wasted as it gave them context and confidence in the final decision, but InfluxDB’s simplicity would have been apparent within an afternoon.&lt;/p&gt;

&lt;h2 id="migration-process"&gt;Migration process&lt;/h2&gt;

&lt;p&gt;The migration involved three phases over a 3-month period: dual writing to InfluxDB and the existing Prometheus setup, validation, and finally, decommissioning the Prometheus infrastructure.&lt;/p&gt;

&lt;h4 id="phase-1-dual-writing-via-vector"&gt;Phase 1: Dual-Writing via Vector&lt;/h4&gt;

&lt;p&gt;The first move was to make the same metrics flow into both systems at once. Mumu added InfluxDB as a second sink alongside Prometheus in their existing Vector pipeline, so every metric was being written to both simultaneously. That parallel run is what made the eventual cutover risk-free by allowing the team to confirm performance and validate both systems against each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migrating to InfluxDB is made easy using AI agents.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;About 80% of the migration work, such as Vector configuration changes, the dual-write sink setup, and the boilerplate around the new HTTP drivers in Go and TypeScript, was  generated by coding agents.&lt;/p&gt;

&lt;p&gt;A migration becomes a lot less daunting when the routine work compresses into hours, but what really made this work was what the agent had to work with on the InfluxDB side. InfluxDB 3 exposes a full REST API with a published &lt;a href="https://docs.influxdata.com/influxdb3/enterprise/api/"&gt;OpenAPI specification&lt;/a&gt;. When an AI agent can read that contract directly, it doesn’t have to guess at parameter names from stale blog posts or hallucinate endpoint shapes from vague documentation. It reads the spec, generates correct client code, and gets the integration right on the first pass. InfluxDB also has an &lt;a href="https://docs.influxdata.com/influxdb3/enterprise/admin/mcp-server/"&gt;MCP server&lt;/a&gt; for integrating with AI agents, although it wasn’t used by Mumu.&lt;/p&gt;

&lt;p&gt;This is an important property in a world where agents are doing more and more of the integration work. The systems that will be easiest to adopt over the next few years are not necessarily the ones with the most features, they’re the ones whose APIs are legible to machines.&lt;/p&gt;

&lt;h4 id="phase-2-validation"&gt;Phase 2: Validation&lt;/h4&gt;

&lt;p&gt;Running two systems in parallel only helps if you actually compare them, and this is where the team spent its caution wisely. The validation approach was deliberately simple: they duplicated their Grafana panels side by side, with one panel pulling from Prometheus and an identical panel pulling from InfluxDB. When two panels showing the same metric look identical for weeks on end, confidence accumulates quickly.&lt;/p&gt;

&lt;p&gt;Beyond visual parity, four things got specific attention:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Retention policies&lt;/strong&gt;: Confirming data was being stored at the right granularity and for the expected duration.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tag cardinality&lt;/strong&gt;: Making sure the tagging strategy wouldn’t cause write-performance problems at scale. Keeping cardinality low on high-volume metric streams is a lesson the team internalized early.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Batch write behavior&lt;/strong&gt;: Validating that the NestJS batching logic produced correct time series data with no gaps or duplicates.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dashboard parity&lt;/strong&gt;: Rebuilding key Grafana dashboards from scratch against InfluxDB to confirm they told the same story as their Prometheus equivalents.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id="phase-3-cutover"&gt;Phase 3: Cutover&lt;/h4&gt;

&lt;p&gt;Because Mumu’s Go and TypeScript codebases already had proper abstractions and interfaces for metric delivery, writing a new driver that sent metrics to InfluxDB via the HTTP API required almost no changes to the application code. The abstraction layer in their app code meant that swapping the metrics backend was a contained, well-scoped task rather than a sprawling refactor.&lt;/p&gt;

&lt;p&gt;The TypeScript driver came in at around 160 lines of code, largely because the team leaned on the official InfluxDB 3 client library package. The Go implementation was slightly longer due to manual HTTP handling, retry logic, and error handling, but was still a straightforward, bounded piece of work. Once the drivers were in place, the team decommissioned Prometheus for business metrics and declared the migration complete.&lt;/p&gt;

&lt;h2 id="benefits-of-influxdb-3from-150-to-560-metrics"&gt;Benefits of InfluxDB 3—from 150 to 560 metrics&lt;/h2&gt;

&lt;p&gt;Before InfluxDB, Mumu collected around 150 metrics. Today, they collect 560 metrics, and that number is constantly increasing.&lt;/p&gt;

&lt;p&gt;That growth didn’t come from a dedicated instrumentation initiative. There was no mandate, no quarter-long observability push, it happened organically because &lt;strong&gt;adding a new metric became a one-line HTTP call&lt;/strong&gt;. When friction drops that far, engineers instrument things they would previously have skipped.&lt;/p&gt;

&lt;p&gt;The number is less a measure of throughput than a measure of how much the team’s relationship with its own data changed once the cost of asking a question fell to nearly zero. And because metric delivery was suddenly cheap, Mumu started instrumenting things that would have seemed impractical before:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Operational automation&lt;/strong&gt;: Mumu sends a metric for every command executed on their servers, with automations built on top using MsgGO, and certain commands automatically trigger a Slack alert. The result is passive visibility into operational activity with no manual reporting required.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CI/CD observability&lt;/strong&gt;: They emit metrics from their Bitbucket pipelines, including how long each pipeline runs. Over time, this has established a baseline for normal build duration, making regressions easy to spot.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Per-developer environments&lt;/strong&gt;: Every developer tags their metrics with an &lt;code class="language-markup"&gt;env&lt;/code&gt; field set to their local environment name, such as &lt;code class="language-markup"&gt;local:john&lt;/code&gt;, &lt;code class="language-markup"&gt;local:kate&lt;/code&gt;, and so on. Each developer can observe their own environment in Grafana, test new instrumentation locally before it ships, and build personal dashboards, all without polluting shared production data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;General script instrumentation&lt;/strong&gt;: Bash scripts, custom CLI commands, and database migration durations during deployments are all now tracked, where before each would have demanded disproportionate effort.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="sql-on-time-series-data"&gt;SQL on time series data&lt;/h2&gt;

&lt;p&gt;Volume was not the only shift. InfluxDB 3’s SQL support meaningfully improved Mumu’s ability to build dashboards and debug metric data. Before the migration, querying time series data meant learning a specialized query language and reasoning about its particular semantics. With SQL, any engineer on the team can write an ad-hoc query to investigate a metric anomaly, validate that a new event is being tracked correctly, or prototype a Grafana panel without consulting documentation.&lt;/p&gt;

&lt;p&gt;The qualitative win is harder to put a number on, but is equally important: the metrics are now trusted. Engineering time that used to go into questioning whether a dashboard was telling the truth now goes into acting on what it shows.&lt;/p&gt;

&lt;h2 id="architecture-overview"&gt;Architecture overview&lt;/h2&gt;

&lt;p&gt;Mumu runs entirely on its own dedicated servers, giving the team full control, room for hardware-level optimization, and predictable costs. The application layer runs on Docker, with services written in Go and NestJS; Go handles core infrastructure-level work while NestJS handles application layer operations.&lt;/p&gt;

&lt;p&gt;Metrics reach InfluxDB along two paths. Vector collects and transforms log-based metrics from the server environment and forwards them to InfluxDB. The Go and NestJS services send business and application metrics directly over the HTTP API.&lt;/p&gt;

&lt;p&gt;The tagging strategy reflects that split. Server-level and infrastructure metrics carry richer tag sets like &lt;code class="language-markup"&gt;env&lt;/code&gt;, &lt;code class="language-markup"&gt;container&lt;/code&gt;, &lt;code class="language-markup"&gt;process_name&lt;/code&gt;, &lt;code class="language-markup"&gt;process_instance&lt;/code&gt;, and &lt;code class="language-markup"&gt;service&lt;/code&gt;. Business and application metrics are tagged more lightly, typically just &lt;code class="language-markup"&gt;env&lt;/code&gt; plus a small number of domain-specific identifiers. On the NestJS side, metrics are batched and flushed either every 60 seconds or when the batch size crosses a configured threshold, which is a configuration the team continues to tune to balance data freshness against RAM usage and write overhead. Grafana sits on top of it all, querying InfluxDB directly.&lt;/p&gt;

&lt;h2 id="future-plans-for-utilizing-influxdb-3"&gt;Future plans for utilizing InfluxDB 3&lt;/h2&gt;

&lt;p&gt;For Mumu, InfluxDB has unlocked more than just an internal observability story. The team is now actively building toward making it a first-class part of their product surface.&lt;/p&gt;

&lt;p&gt;The most immediate project is integrating InfluxDB as a delivery target inside MsgGO. Today, MsgGO routes messages to Slack, Telegram, Discord, Email, SMS, and Webhooks. Adding InfluxDB as a target means any system already sending events through MsgGO like  contact forms, deployment notifications, server alerts, and application events, can now route structured event data directly into InfluxDB with no additional integration work. Since Mumu uses MsgGO heavily inside its own infrastructure, this would pay off immediately in its own workflows, with the customer-facing benefits coming close behind.&lt;/p&gt;

&lt;p&gt;Further out, the team is evaluating whether to move user-activity statistics that are currently kept as activity records in a NoSQL database into InfluxDB. That data is inherently time series in nature, and putting it in InfluxDB would let them expose richer usage analytics inside the Mumu dashboard without needing a separate query infrastructure. And they want to lean on InfluxDB’s SQL interface to drive product decisions, using internal usage metrics to understand which modules see the most engagement, where users drop off, and how feature adoption shifts after a release.&lt;/p&gt;
</description>
      <pubDate>Thu, 25 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/core-ai-user-mumu/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/core-ai-user-mumu/</guid>
      <category>Developer</category>
      <category>Use Cases</category>
      <author>Charles Mahler (InfluxData)</author>
    </item>
    <item>
      <title>Telegraf Enterprise Now Generally Available: Manage Telegraf Fleets at Scale</title>
      <description>&lt;p&gt;&lt;strong&gt;Summary: Telegraf Enterprise is now generally available. It combines Telegraf Controller, a centralized management console for Telegraf, with official support from InfluxData. Open source Telegraf remains unchanged. Telegraf Controller is free to start with built-in limits, while a Telegraf Enterprise license unlocks higher-scale limits, audit logging, LDAP/OIDC integration, and commercial support.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Telegraf has become the standard for collecting telemetry across cloud, edge, and physical infrastructure. With more than five billion downloads and 400+ official plugins, Telegraf is the open source standard to connect virtually any data source to any destination.&lt;/p&gt;

&lt;p&gt;Over the years, we’ve seen Telegraf evolve from a lightweight collection agent into a foundational part of production infrastructure. But as deployments grow, the challenge shifts from collecting telemetry to managing the systems that collect it. Large Telegraf deployments require consistent configurations across environments, clear visibility into fleet health, and safe rollout of changes to thousands of agents. Many teams rely on scripts, internal tools, and manual processes to manage this, but these approaches quickly break down as deployments scale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.influxdata.com/products/telegraf-enterprise/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=telegraf-enterprise-ga&amp;amp;utm_content=blog"&gt;Telegraf Enterprise&lt;/a&gt; is now generally available to address these challenges, giving teams a centralized way to manage configurations, monitor fleet health, and operate Telegraf deployments with tens of thousands of agents from a single system.&lt;/p&gt;

&lt;h2 id="centralized-control-for-large-telegraf-deployments"&gt;Centralized control for large Telegraf deployments&lt;/h2&gt;

&lt;p&gt;As Telegraf becomes more deeply embedded in production environments, visibility and consistency become increasingly important. Teams need to understand which agents are healthy, what configurations are running across environments, and whether changes have been deployed successfully. They also need a way to manage differences between regions, customers, and environments without creating hundreds of nearly identical configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telegraf Enterprise combines Telegraf Controller, a centralized management console for Telegraf, with official InfluxData support&lt;/strong&gt;. Telegraf Controller provides a centralized way to manage those deployments. Teams can create and manage configurations centrally, assign them to agents, and monitor fleet health from a single interface. Configuration templates and parameter substitution make it possible to standardize shared configurations while still allowing environment-specific values where needed.&lt;/p&gt;

&lt;p&gt;&lt;img class="py-10" src="//images.ctfassets.net/o7xu9whrs0u9/2k07vZhwHTnp5F2uhSWUVj/0b624827c8409d6db8fec263c5cdefb9/telegraf-enterprise-agents.png" alt="telegraf-enterprise-agents" /&gt;&lt;/p&gt;

&lt;p&gt;For organizations operating large Telegraf deployments, consistency is just as important as collection. Keeping configurations aligned across thousands of agents, while continuing to work with existing automation systems, can quickly become an operational challenge.&lt;/p&gt;

&lt;p&gt;&lt;img class="py-10" src="//images.ctfassets.net/o7xu9whrs0u9/30YgKR4570eWgHjrLjv177/947f9741de71f9494a4f60e97fb6c3b4/telegraf-config-builder.png" alt="telegraf-config-builder" /&gt;&lt;/p&gt;

&lt;p&gt;The visual configuration builder makes it easier to create and review configurations across Telegraf’s 400+ plugin ecosystem without manually authoring every line of TOML.&lt;/p&gt;

&lt;p&gt;&lt;img class="py-10" src="//images.ctfassets.net/o7xu9whrs0u9/5pgPpQFjD9aNpl0Jry5Ynx/746773079100ec12f0a61cbb27ee5efa/telegraf-enterprise-configs.png" alt="telegraf-enterprise-configs" /&gt;&lt;/p&gt;

&lt;p&gt;“We run thousands of Telegraf agents across diverse customer environments. Telegraf Controller will help us use our existing automation tools to keep agent configurations consistent and up to date across our fleet as we continue expanding our observability platform.” – Poul H. Sørensen, Senior Systems Consultant at Orange Business&lt;/p&gt;

&lt;p&gt;Open source Telegraf remains unchanged. The agent, the plugin ecosystem, and community continue as they always have. Telegraf Controller’s free tier supports up to 20 configs and 100 agents, making it easy to get started with centralized fleet management.&lt;/p&gt;

&lt;h2 id="what-an-enterprise-license-buys-you"&gt;What an Enterprise license buys you&lt;/h2&gt;

&lt;p&gt;As your fleet grows and more people touch your Telegraf configurations, the free tier’s limits start becoming constraints. Telegraf Enterprise removes those constraints and scales to your needs, offering:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Raised scale limits&lt;/strong&gt;: The free version of Telegraf Controller makes it easy to get started and evaluate the product. A Telegraf Enterprise license raises the agent and configuration limits based on your licensed entitlement, allowing Telegraf Controller to grow with the size of your fleet.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Audit logging&lt;/strong&gt;: Telegraf Enterprise records security-relevant and administrative events, including configuration changes, permission updates, agent actions, login activity, and license changes. This provides clearer operational history for troubleshooting, compliance, and security investigations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Identity provider integration&lt;/strong&gt;: Organizations can integrate Telegraf Enterprise with LDAP and OIDC rather than maintaining a separate user directory. For organizations using SSO or MFA through an identity provider, Telegraf Controller can integrate into that existing model.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="official-support-for-telegraf"&gt;Official support for Telegraf&lt;/h2&gt;

&lt;p&gt;Telegraf Enterprise adds an official InfluxData support path for organizations running Telegraf as part of their critical production infrastructure. Customers get support for both Telegraf Controller and the Telegraf agent, including installation, configuration, operational guidance, and troubleshooting assistance.&lt;/p&gt;

&lt;h2 id="upgrade-in-place"&gt;Upgrade in place&lt;/h2&gt;

&lt;p&gt;If you’re already running Telegraf Controller, there’s no separate Enterprise deployment or migration process. Add a valid license to your existing installation and the Enterprise capabilities unlock in place. The same deployment, agents, and configurations remain in place while additional scale, security, and support capabilities become available.&lt;/p&gt;

&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;

&lt;p&gt;Telegraf Controller is available today with a free tier. 
Telegraf solved the problem of collecting telemetry from almost anywhere; Telegraf Enterprise helps teams operate that collection layer as it grows into critical infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.influxdata.com/telegraf/controller/install/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=telegraf-enterprise-ga&amp;amp;utm_content=blog"&gt;&lt;strong&gt;Download and install Telegraf Controller&lt;/strong&gt;&lt;/a&gt; or &lt;a href="http://influxdata.com/contact-sales-telegraf-enterprise/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=telegraf-enterprise-ga&amp;amp;utm_content=blog"&gt;&lt;strong&gt;contact us about Telegraf Enterprise&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 24 Jun 2026 06:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/telegraf-enterprise-ga/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/telegraf-enterprise-ga/</guid>
      <category>Developer</category>
      <category>Product</category>
      <category>news</category>
      <author>Scott Anderson (InfluxData)</author>
    </item>
    <item>
      <title>Why Relational Databases Fail Satellite Telemetry</title>
      <description>&lt;p&gt;Satellite operations depend on telemetry as the primary interface to systems that teams cannot directly inspect. Once a spacecraft reaches orbit, signals such as battery levels, temperature, signal strength, and fault codes become the foundation for understanding system health and maintaining control.&lt;/p&gt;

&lt;p&gt;Telemetry streams continuously, so the underlying data system becomes a critical control point that needs to handle a constant, heavy flow of data. When that system cannot ingest, query, and manage data efficiently, dashboards lag, investigations slow, and the clarity teams rely on begins to erode.&lt;/p&gt;

&lt;h2 id="relational-data-vs-satellite-telemetry"&gt;Relational data vs. satellite telemetry&lt;/h2&gt;

&lt;p&gt;Relational data organizes information into structured records with consistent fields and defined relationships. A business application might represent customers, orders, and products as related datasets, making it easy to answer questions such as which customer placed an order or which products were included in a purchase. This relational model works well when information is relatively stable and relationships between records are clearly defined.&lt;/p&gt;

&lt;p&gt;Satellites are dynamic systems. Operators are not tracking static records or one-time transactions, but monitoring systems that change continuously. Telemetry arrives as a stream of time-stamped measurements, or &lt;a href="https://www.influxdata.com/time-series-database/#what-is-time-series"&gt;time series data&lt;/a&gt;. Each value depends on when the system recorded it and its change relative to earlier readings.&lt;/p&gt;

&lt;p&gt;A single battery reading of 80% may appear normal. In isolation, it provides limited insight. If that value declined from 95% over the past hour, the same reading indicates a different condition. Operators need the sequence, rate of change, and surrounding context to determine whether a change reflects normal behavior, an emerging anomaly, or a sign of impending failure.&lt;/p&gt;

&lt;p&gt;As telemetry volume grows, individual readings lose meaning without historical continuity. Teams need to understand how values change over time, not just what they are at one moment. As that requirement grows, relational systems show their limits.&lt;/p&gt;

&lt;h2 id="where-relational-databases-start-to-strain"&gt;Where relational databases start to strain&lt;/h2&gt;

&lt;p&gt;PostgreSQL- and MySQL-style databases can support early telemetry workloads, especially when teams already use them for operational data. The strain begins when a transactional, row-oriented database becomes the primary store for high-volume telemetry.&lt;/p&gt;

&lt;p&gt;For these systems, telemetry challenges typically appear in three areas: query speed, data lifecycle management, and storage efficiency.&lt;/p&gt;

&lt;h4 id="speed-and-query-performance"&gt;Speed and Query Performance&lt;/h4&gt;

&lt;p&gt;Satellite operations rely on dashboards, alerts, and analytics to maintain visibility into system health. When a subsystem begins overheating or signal strength drops during a contact window, teams need recent data immediately.&lt;/p&gt;

&lt;p&gt;Relational databases such as PostgreSQL and MySQL can store telemetry, but they don’t optimize for high-volume time series workloads. As measurements accumulate, queries must process larger datasets, indexes expand, and the database spends more resources balancing continuous writes with analytical reads.&lt;/p&gt;

&lt;p&gt;Slow queries affect more than latency. Delayed dashboards and alerts reduce the time teams have to detect anomalies, investigate issues, and make operational decisions. Teams may need additional infrastructure and ongoing tuning to keep systems responsive, increasing the cost of managing mission data.&lt;/p&gt;

&lt;h4 id="time-awareness-and-data-lifecycle"&gt;Time Awareness and Data Lifecycle&lt;/h4&gt;

&lt;p&gt;Telemetry does not retain the same value over time. Recent measurements are critical for real-time monitoring, &lt;a href="https://www.influxdata.com/glossary/anomaly-detection/"&gt;anomaly detection&lt;/a&gt;, and fault investigation, where operators need full-resolution data. Older data remains useful, but teams more often use it for trend analysis, reporting, and long-term performance evaluation.&lt;/p&gt;

&lt;p&gt;PostgreSQL- and MySQL-style transactional databases do not manage this telemetry lifecycle by default. Teams can use partitions, scheduled jobs, archive tables, or custom pipelines to retain, move, or summarize older records, but those processes require separate design, maintenance and governance. Other relational systems handle historical analysis differently. Analytical databases and data warehouses can support large-scale scans and reporting, but continuous telemetry creates separate tradeoffs around ingest speed, data freshness, cost, and operational responsiveness.&lt;/p&gt;

&lt;p&gt;For telemetry stores,  lifecycle management becomes ongoing operational work. Without a clear strategy, raw measurements continue to accumulate, historical datasets grow harder to manage and queries may process more full-resolution data than operators need for long-term analysis.&lt;/p&gt;

&lt;h4 id="storage-and-scale"&gt;Storage and Scale&lt;/h4&gt;

&lt;p&gt;Satellite telemetry generates large volumes of measurements, many of which share the same contextual information. Spacecraft identifiers, subsystem names, and sensor metadata often repeat across millions of records while only the timestamp and value change.&lt;/p&gt;

&lt;p&gt;Telemetry schemas can also become large and sparse as missions add more sensors, subsystems, and measurement types. Not every field applies to every reading, but the database still has to store, index, and manage the growing structure around those measurements. As the number of sources and dimensions increases, data volume grows rapidly, and &lt;a href="https://www.influxdata.com/glossary/cardinality/"&gt;cardinality&lt;/a&gt; expands, multiplying the number of unique series the system must store.&lt;/p&gt;

&lt;p&gt;PostgreSQL- and MySQL-style transactional databases are not optimized for this pattern. Row-oriented storage works well when each row represents a distinct transaction or operational record. Telemetry behaves differently. It repeats similar context across continuous streams of time-ordered measurements, which can make compression less efficient and increase storage overhead.&lt;/p&gt;

&lt;p&gt;Over time, organizations may allocate more infrastructure simply to retain and manage telemetry. What begins as a manageable archive can become increasingly expensive to maintain, especially when long-term historical data remains important for analysis and mission planning.&lt;/p&gt;

&lt;p&gt;These limitations stem from storage models designed for transactional records rather than continuous, time-ordered measurements.&lt;/p&gt;

&lt;h2 id="time-series-databases-a-better-fit-for-time-series-data"&gt;Time series databases: A better fit for time-series data&lt;/h2&gt;

&lt;p&gt;Time series databases are purpose-built for data that changes over time. Instead of organizing information around static records and relationships, they structure data around timestamps, time ranges, and continuous streams of measurements.&lt;/p&gt;

&lt;p&gt;This design matches how satellite telemetry behaves. Operators need to monitor recent readings, compare values across time windows, identify trends, and investigate anomalies using historical context. The database must support both high-ingest workloads and fast access to time-based data.&lt;/p&gt;

&lt;p&gt;InfluxDB is a time series database built for these requirements. It provides a data layer optimized for telemetry, helping satellite teams power real-time dashboards, alerts, anomaly detection, and long-term analysis while avoiding many of the performance and scalability challenges that emerge when telemetry is stored in a relational database.&lt;/p&gt;

&lt;h4 id="maintaining-query-speed-at-scale"&gt;Maintaining Query Speed at Scale&lt;/h4&gt;

&lt;p&gt;InfluxDB 3 maintains query performance as telemetry volumes grow. Its architecture combines a real-time columnar engine with technologies designed for analytical workloads, helping teams retrieve and analyze large datasets efficiently.&lt;/p&gt;

&lt;p&gt;Telemetry is stored in a columnar format, allowing queries to read only the fields they need instead of scanning entire records. Because data is organized around time, queries can focus on relevant time ranges rather than searching across the full dataset.&lt;/p&gt;

&lt;p&gt;InfluxDB 3 also uses &lt;a href="https://www.influxdata.com/glossary/apache-datafusion/"&gt;Apache DataFusion&lt;/a&gt; to power SQL queries. DataFusion applies filters early and processes data efficiently through &lt;a href="https://www.influxdata.com/glossary/batch-processing-explained/"&gt;batches&lt;/a&gt;, reducing the amount of information that must be scanned and moved during query execution.&lt;/p&gt;

&lt;p&gt;For satellite operations, these optimizations help keep dashboards, alerts, and investigations responsive even as telemetry volumes increase. Teams can access recent measurements and historical trends without the growing query overhead that often affects relational systems handling large-scale time series data.&lt;/p&gt;

&lt;h4 id="managing-data-over-time"&gt;Managing Data Over Time&lt;/h4&gt;

&lt;p&gt;Telemetry does not retain the same value over time. Recent measurements are critical for real-time monitoring, anomaly detection, and fault investigation, where operators need full-resolution data. Older telemetry remains useful, but teams more often use it for trend analysis, reporting, and long-term performance evaluation.&lt;/p&gt;

&lt;p&gt;InfluxDB supports this lifecycle through retention and downsampling. Retention policies define how long data remains available, while downsampling converts older high-frequency telemetry into lower-resolution aggregates that preserve long-term trends.&lt;/p&gt;

&lt;p&gt;This approach helps teams manage telemetry according to how it’s actually used. Recent data can remain detailed and readily accessible for operational workflows, while historical data can be summarized to reduce storage requirements and query costs.&lt;/p&gt;

&lt;p&gt;By automating retention and downsampling, InfluxDB reduces the need for custom cleanup scripts, archive processes, and manual data management. Teams can spend less time maintaining telemetry pipelines while keeping storage growth and query overhead under control.&lt;/p&gt;

&lt;h4 id="reducing-storage-overhead-at-scale"&gt;Reducing Storage Overhead at Scale&lt;/h4&gt;

&lt;p&gt;Telemetry adds both fresh and repeated data. &lt;strong&gt;As missions add sensors, measurement types, and metadata, telemetry schemas can become large, sparse, and expensive to store&lt;/strong&gt;. InfluxDB 3 organizes telemetry in a columnar format built on &lt;a href="https://www.influxdata.com/glossary/apache-arrow/"&gt;Apache Arrow&lt;/a&gt; and &lt;a href="https://www.influxdata.com/glossary/apache-parquet/"&gt;Apache Parquet&lt;/a&gt;, which helps store similar values together and improve compression.&lt;/p&gt;

&lt;p&gt;This matters for satellite workloads. Spacecraft, subsystem, and sensor labels may repeat across large volumes of readings, while different measurements may rely on different fields. A storage model designed for time series data can compress repeated values and sparse data more efficiently than a transactional model that treats each reading like a separate record.&lt;/p&gt;

&lt;p&gt;Stronger compression helps reduce storage overhead as telemetry volume and cardinality grow, allowing teams to retain historical context without carrying the full storage cost of every raw measurement, repeated label, and unused field. InfluxDB 3 also supports architectures that separate compute from storage, giving organizations more flexibility to scale storage and query resources independently as data grows.&lt;/p&gt;

&lt;p&gt;It’s a model that helps slow the growth of storage overhead: satellite teams can keep more telemetry available for analysis while reducing the infrastructure cost of storing large, repetitive telemetry datasets.&lt;/p&gt;

&lt;h2 id="processing-telemetry-beyond-storage"&gt;Processing telemetry beyond storage&lt;/h2&gt;

&lt;p&gt;The value of satellite telemetry lies in understanding and responding to real-time spacecraft behavior. Operational impact comes from turning continuous streams of measurements into timely insights that help teams maintain visibility and make informed decisions with confidence.&lt;/p&gt;

&lt;p&gt;InfluxDB is the foundation that makes that possible. By combining scalable telemetry storage with built-in processing capabilities, it helps satellite teams support real-time monitoring, accelerate analysis, and automate workflows that keep mission operations running smoothly.&lt;/p&gt;

&lt;p&gt;Whether the goal is improving spacecraft health monitoring, reducing investigation time, scaling telemetry infrastructure, or preserving long-term mission insight, InfluxDB helps transform telemetry data into a continuous source of operational value.&lt;/p&gt;

&lt;p&gt;2Get started with &lt;a href="https://www.influxdata.com/products/influxdb/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=why_relational_databases_fail&amp;amp;utm_content=blog"&gt;InfluxDB 3 Core OSS&lt;/a&gt; or &lt;a href="https://www.influxdata.com/products/influxdb3-enterprise/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=why_relational_databases_fail&amp;amp;utm_content=blog"&gt;InfluxDB 3 Enterprise&lt;/a&gt; to build a telemetry platform designed for time series workloads.&lt;/p&gt;
</description>
      <pubDate>Fri, 19 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/why-relational-databases-fail/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/why-relational-databases-fail/</guid>
      <category>Developer</category>
      <author>Allyson Boate (InfluxData)</author>
    </item>
    <item>
      <title>What’s New in InfluxDB 3.10: Performance Beta Expanded with New Enterprise Features </title>
      <description>&lt;p&gt;In our last release, we introduced a beta of performance updates designed for heavier, more complex time series workloads. InfluxDB 3.10 expands that beta to include enterprise features that give teams more control as they scale and manage larger workloads in InfluxDB 3.&lt;/p&gt;

&lt;p&gt;This release adds end-to-end backup and restore, row-level deletes, bulk import from Parquet, user management, and an RBAC preview to the previous performance beta. It also includes cross-database plugin queries, a new readiness endpoint, and compaction improvements for InfluxDB 3 Enterprise. Together, these updates help teams evaluate the next phase of InfluxDB 3 performance and scale with more of the operational tooling they need to manage real workloads.&lt;/p&gt;

&lt;p&gt;We’re inviting customers to test this next phase of InfluxDB 3 performance and scale, share feedback, and help shape the path to general availability.&lt;/p&gt;

&lt;h2 id="expanded-capabilities-for-the-performance-beta"&gt;Expanded capabilities for the performance beta&lt;/h2&gt;

&lt;p&gt;The performance improvements &lt;a href="https://www.influxdata.com/blog/influxdb-3-9/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=influxdb_3_10_expanded_beta&amp;amp;utm_content=blog"&gt;we previewed in InfluxDB 3.9&lt;/a&gt; continue to mature in beta. These updates are designed for teams testing heavier time series workloads, including higher ingest, wider schemas, sparse data, and more demanding recent-data queries.&lt;/p&gt;

&lt;p&gt;The beta remains opt-in and is not yet the default, so existing deployments continue running unaffected unless teams explicitly enable it with the &lt;code class="language-markup"&gt;--use-pacha-tree&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Once users opt in to the beta, InfluxDB 3.10 adds operational capabilities, so teams can do more than test raw performance. They can protect data, recover from known-good states, remove bad or unnecessary rows, and bring existing Parquet datasets into InfluxDB 3 for evaluation. That matters for teams working with real production patterns, where data rarely arrives perfectly clean and workloads rarely stay fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The following capabilities are available only when using the performance beta, enabled with the -&lt;code class="language-markup"&gt;-use-pacha-tree&lt;/code&gt; flag&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;End-to-end backup and restore&lt;/strong&gt;: You can now run full backups that capture cluster state and compacted data for easy rollbacks. Restores run asynchronously, allowing you to recover data into a fresh store for disaster recovery or roll a live cluster back to an earlier point in time. We’ll soon be adding incremental restores to give you even more control over your restore points.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Row-level deletes&lt;/strong&gt;: Teams can now remove specific rows based on time ranges or tag predicates rather than dropping entire tables when data needs to be purged. The compactor applies these changes asynchronously in the background, allowing teams to clean up production data without interrupting operations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bulk import from Parquet&lt;/strong&gt;: A new bulk-import function makes it easier to bring historical or external data into InfluxDB 3. Teams can point InfluxDB at a generic Parquet file or an entire directory, use simple column mappings, and ingest each file as an independent import job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="user-authentication-and-rbac-preview"&gt;User authentication and RBAC preview&lt;/h2&gt;

&lt;p&gt;As time series workloads become more central to production systems, access control becomes increasingly important. The same database may support operators monitoring live systems, developers building applications, analysts exploring historical data, and automated services writing or transforming telemetry.&lt;/p&gt;

&lt;p&gt;InfluxDB 3.10 Enterprise introduces a preview of multi-user authentication and role-based access control (RBAC). This feature is turned off by default for this release.&lt;/p&gt;

&lt;p&gt;When enabled, operators can configure traditional username and password logins that issue JWTs, or opt for external identity management through OAuth and OIDC. 3.10 also introduces built-in roles, including Admin, Auditor, and Member, to enforce proper boundaries across your teams. Best of all, your existing token workflows will continue to work exactly as they do today without any breaking changes.&lt;/p&gt;

&lt;h2 id="general-updates-and-improvements"&gt;General updates and improvements&lt;/h2&gt;

&lt;p&gt;InfluxDB 3.10 also includes several capabilities that work across all deployments to streamline data pipelines and improve cluster management.&lt;/p&gt;

&lt;h4 id="cross-database-plugin-queries"&gt;Cross-Database Plugin Queries&lt;/h4&gt;

&lt;p&gt;Time series data often moves through stages: raw telemetry, cleaned data, downsampled rollups, forecasts, anomaly scores, and application-ready views. Those stages may live in different databases, but teams still need to connect them without building unnecessary external pipelines.&lt;/p&gt;

&lt;p&gt;In 3.10, Processing Engine plugins are no longer restricted to querying their own database. Now, a plugin can query any database residing on that node. This unlocks read-from-one, write-to-another data pipelines, such as reading raw telemetry from a staging database and writing compacted rollups or machine learning forecasts to a production database.&lt;/p&gt;

&lt;h4 id="readiness-endpoint"&gt;Readiness Endpoint&lt;/h4&gt;

&lt;p&gt;Production deployments need health checks that reflect whether a node can actually serve traffic, not just whether a process is running. InfluxDB 3.10 adds a new /ready endpoint. Instead of a basic uptime check, this endpoint verifies whether the node can successfully reach its underlying object store, giving operators a more reliable signal for traffic routing.&lt;/p&gt;

&lt;h4 id="improved-compaction"&gt;Improved Compaction&lt;/h4&gt;

&lt;p&gt;Under heavy ingest, compaction needs to keep pace with incoming writes so query nodes can access optimized data. When compaction stalls, the path from raw writes to efficient queries slows down. InfluxDB 3.10 introduces parallel compaction, ensuring that query nodes access fully compacted data more quickly and serve queries faster.&lt;/p&gt;

&lt;h2 id="get-started-with-influxdb-310"&gt;Get started with InfluxDB 3.10&lt;/h2&gt;

&lt;p&gt;InfluxDB 3.10 is available now. To get started, download the latest version or pull the newest Docker image for Core or Enterprise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.influxdata.com/products/influxdb/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=influxdb_3_10_expanded_beta&amp;amp;utm_content=blog"&gt;InfluxDB 3 Core&lt;/a&gt; remains free and open source under MIT and Apache 2 licenses, optimized for recent data and local workloads. &lt;a href="https://www.influxdata.com/products/influxdb3-enterprise/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=influxdb_3_10_expanded_beta&amp;amp;utm_content=blog"&gt;InfluxDB 3 Enterprise&lt;/a&gt; adds long-range querying, clustering, advanced security, and full operational tooling for production deployments.&lt;/p&gt;

&lt;p&gt;Check out the docs (&lt;a href="https://docs.influxdata.com/influxdb3/core/release-notes/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=influxdb_3_10_expanded_beta&amp;amp;utm_content=blog"&gt;Core&lt;/a&gt;, &lt;a href="https://docs.influxdata.com/influxdb3/enterprise/release-notes/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=influxdb_3_10_expanded_beta&amp;amp;utm_content=blog"&gt;Enterprise&lt;/a&gt;), try the release in your environment, and share your feedback in Discord or the Community Slack. We want your feedback as the performance beta continues to mature.&lt;/p&gt;
</description>
      <pubDate>Wed, 17 Jun 2026 12:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/influxdb-3-10/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/influxdb-3-10/</guid>
      <category>Product</category>
      <category>Developer</category>
      <author>Peter Barnett (InfluxData)</author>
    </item>
    <item>
      <title>Generate Synthetic Time Series Data in InfluxDB 3</title>
      <description>&lt;p&gt;Getting InfluxDB 3 up and running is a pretty lightweight process with the &lt;a href="https://docs.influxdata.com/influxdb3/core/install/#quick-install-for-linux-and-macos"&gt;installation script&lt;/a&gt;. Getting time series data into it is the next step, and for exploration, basic testing, or scenarios where you don’t have a stream of time series data ready to write, that can be a point of friction.&lt;/p&gt;

&lt;p&gt;That hurdle is particularly high when you want to test the rest of the system around the data you’d be writing: dashboards, alerts, replication, network connectivity, edge devices, server sizing, or Processing Engine workflows—you don’t always have the ability to start writing production data into a freshly-installed database, or you may not have that data yet.&lt;/p&gt;

&lt;p&gt;Two new InfluxDB 3 plugins help with exactly that: the Bird Tracking Simulator and the Signal Generator. Both are scheduled plugins that generate data directly to InfluxDB 3, making it easy to start writing realistic sample data with a single trigger. The Bird Tracking Simulator creates synthetic bird telemetry, while the Signal Generator creates configurable waveform data for sensor-like or metric-like use cases.&lt;/p&gt;

&lt;h2 id="why-generate-sample-data-this-way"&gt;Why generate sample data this way?&lt;/h2&gt;

&lt;p&gt;A lot of InfluxDB workflows are easier to understand once data is actively moving through the system:a dashboard is easier to build when the line and the most recent datapoint keep changing, an alert is easier to validate when values cross a threshold, edge replication is easier to test when writes are arriving continuously, and a small server or single-board computer is easier to evaluate when you can watch how it behaves under a steady stream of points.&lt;/p&gt;

&lt;p&gt;These plugins are meant to make that first step simple. Create a database, create a trigger, and InfluxDB 3 starts generating data on a schedule. From there, you can query it, visualize it, replicate it, downsample it, or use it as input for other Processing Engine plugins.&lt;/p&gt;

&lt;h2 id="bird-tracking-simulator"&gt;Bird Tracking Simulator&lt;/h2&gt;

&lt;p&gt;The Bird Tracking Simulator generates a stream of synthetic bird telemetry. On its first run, it creates a persistent flock of named birds, assigns each bird a variety of tags, such as species, name, and range, and stores the flock in the Processing Engine cache. Each scheduled execution of the plugin advances the flock by updating a number of measurements, including speed, heading, latitude, and longitude, with the birds going on &lt;a href="https://en.wikipedia.org/wiki/Random_walk"&gt;random walks&lt;/a&gt; within a predefined range for each species.&lt;/p&gt;

&lt;p&gt;The shape of the data is useful for a few reasons. It has multiple entities,  tags, and geospatial fields. It changes over time in a way that is easy to inspect visually. That makes it a good fit for testing dashboards, map panels, edge replication, and basic query patterns that group or filter by tags.&lt;/p&gt;

&lt;p&gt;The plugin writes to the &lt;code class="language-markup"&gt;bird_tracking&lt;/code&gt; measurement. Its configuration is also intentionally small, specified with simple trigger arguments: &lt;code class="language-markup"&gt;bird_count&lt;/code&gt; controls how many persistent birds are tracked, and &lt;code class="language-markup"&gt;points_per_bird&lt;/code&gt; controls how many movement points each bird emits per scheduled run. The defaults are 25 birds and 1 point per bird. The number of data points the plugin generates is a simple product of these two options and the trigger specification for how often the plugin runs.&lt;/p&gt;

&lt;p&gt;The plugin requires &lt;a href="https://pypi.org/project/Faker/"&gt;Faker&lt;/a&gt;, so install that first:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 install package Faker&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then create a database and a scheduled trigger:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create database sample_data

influxdb3 create trigger \
  --database sample_data \
  --path "gh:influxdata/bird_data_simulator/bird_data_simulator.py" \
  --trigger-spec "every:10s" \
  --trigger-arguments bird_count=10,points_per_bird=10 \
  bird_tracking_demo&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the trigger has run a few times, query the generated data:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query \
  --database sample_data \
  "SELECT * FROM bird_tracking ORDER BY time DESC LIMIT 5"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For a denser stream, increase the flock size, increase the points per bird, or adjust the trigger interval. That gives you a simple way to create a steady stream of entity-oriented time series data. You can use it to populate dashboards, test writes across a network, or quickly confirm that a new InfluxDB 3 setup is receiving, storing, and querying data as expected.&lt;/p&gt;

&lt;h2 id="signal-generator"&gt;Signal Generator&lt;/h2&gt;

&lt;p&gt;The Signal Generator achieves many of the same things, but by generating numeric signals rather than named entities. The default preset produces a signal centered around 30, with a slow sine trend, Gaussian noise, and occasional spikes. It uses only the Python standard library, supports configurable measurement names, field names, tags, and point resolution, and can compose multiple waveform types together. Supported waveform types include sine, square, triangle, sawtooth, noise, and spike.&lt;/p&gt;

&lt;p&gt;That makes it useful for testing dashboards, threshold checks, alerting behavior, anomaly detection, and any workflow that requires a predictable yet non-static stream of numeric values. A line with trend, noise, and the occasional spike gives you something closer to the patterns you usually care about when working with time series data.&lt;/p&gt;

&lt;p&gt;The simplest version uses the default preset:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create database signals

influxdb3 create trigger \
  --database signals \
  --path "gh:influxdata/signal_generator/signal_generator.py" \
  --trigger-spec "every:10s" \
  signal_basic&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the trigger has run, query the latest generated values:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query \
  --database signals \
  "SELECT time, value FROM signal ORDER BY time DESC LIMIT 10"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also aggregate the generated signal over time:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-sql"&gt;influxdb3 query \
  --database signals \
  "SELECT
     time_bucket(time, INTERVAL '1 minute') AS minute,
     AVG(value) AS avg_value,
     MIN(value) AS min_value,
     MAX(value) AS max_value
   FROM signal
   WHERE time &amp;gt; now() - INTERVAL '1 hour'
   GROUP BY minute
   ORDER BY minute DESC"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For custom waveforms, the plugin can be configured with JSON arguments through InfluxDB 3 Explorer or the Processing Engine API. That lets you define signals for different measurements, fields, and tags, or stack waveforms together to create the shape you want.&lt;/p&gt;

&lt;p&gt;For example, you might create one signal that looks like a temperature sensor, another that behaves like CPU utilization, and another that emits occasional spikes to test an alerting path. Because each trigger can have its own configuration, you can build out a small set of synthetic streams that exercise different parts of your system.&lt;/p&gt;

&lt;h2 id="lightweight-data-generation-for-influxdb-3"&gt;Lightweight data generation for InfluxDB 3&lt;/h2&gt;

&lt;p&gt;The Bird Tracking Simulator and Signal Generator are small plugins, but they solve a useful problem: they make it easy to get fresh time series data flowing through InfluxDB 3 with very little setup, allowing you to test your deployment and ensure data is flowing to and from every system downstream of your InfluxDB instance.&lt;/p&gt;

&lt;p&gt;Use the Bird Tracking Simulator when you want moving, entity-oriented telemetry with tags and location fields. Use the Signal Generator when you want numeric signal data for dashboards, alerts, thresholds, and processing workflows.&lt;/p&gt;

&lt;p&gt;Check out the plugins in the &lt;a href="https://github.com/influxdata/influxdb3_plugins/tree/main/influxdata/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=generate_synthetic_data&amp;amp;utm_content=blog"&gt;InfluxDB 3 plugin repository&lt;/a&gt;, try them on the hardware you already have, and use them as a quick way to exercise InfluxDB 3, the Processing Engine, and the systems connected to them.&lt;/p&gt;
</description>
      <pubDate>Fri, 12 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/generate-synthetic-data/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/generate-synthetic-data/</guid>
      <category>Developer</category>
      <author>Cole Bowden (InfluxData)</author>
    </item>
    <item>
      <title>Building a Predictive Maintenance Plugin with the InfluxDB 3 Processing Engine </title>
      <description>&lt;p&gt;Predictive maintenance is one of the most compelling use cases for time series data. Instead of waiting for equipment to fail or servicing it on a fixed calendar regardless of condition, you watch the live sensor data and act when it indicates that a failure is coming. That “watch the data and act” loop is exactly what the InfluxDB 3 Processing Engine was built for.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll build a working predictive maintenance plugin from scratch. We’ll install &lt;a href="https://docs.influxdata.com/influxdb3/core/install/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=predictive_maintenance_plugin_tutorial&amp;amp;utm_content=blog"&gt;InfluxDB 3 Core&lt;/a&gt;, load a well-known public dataset of jet engine sensor data, write a Python plugin that runs inside the database to estimate each engine’s Remaining Useful Life (RUL), and have it raise maintenance alerts automatically. By the end, you’ll have an end-to-end system that you can adapt to pumps, motors, HVAC units, CNC machines, or any other instrumented asset.&lt;/p&gt;

&lt;h2 id="what-were-building"&gt;What we’re building&lt;/h2&gt;

&lt;p&gt;Here’s the architecture at a glance:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Sensor data lands in InfluxDB 3 Core. We’ll use &lt;a href="https://www.kaggle.com/datasets/bishals098/nasa-turbofan-engine-degradation-simulation"&gt;NASA’s C-MAPSS turbofan engine degradation dataset&lt;/a&gt;, replayed into a &lt;code class="language-markup"&gt;sensors&lt;/code&gt; table as if it were arriving live from a fleet of engines.&lt;/li&gt;
  &lt;li&gt;A &lt;a href="https://docs.influxdata.com/influxdb3/core/plugins/"&gt;scheduled plugin&lt;/a&gt; runs every minute. It queries the most recent sensor readings per engine, computes a health/degradation score, and converts that into an estimated Remaining Useful Life.&lt;/li&gt;
  &lt;li&gt;The plugin writes its conclusions back into the database. RUL estimates go into a &lt;code class="language-markup"&gt;rul_estimates&lt;/code&gt; table, and when an engine crosses a danger threshold, the plugin writes a row into a &lt;code class="language-markup"&gt;maintenance_alerts&lt;/code&gt; table and logs a warning.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key idea is that the analysis logic lives &lt;em&gt;embedded in the database&lt;/em&gt;. There’s no separate service to deploy, scale, or keep in sync. When data arrives, the engine acts on it.&lt;/p&gt;

&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A Linux or macOS machine (Windows works too via the installer or Docker; commands below assume a Unix-like shell)&lt;/li&gt;
  &lt;li&gt;Command-line access&lt;/li&gt;
  &lt;li&gt;Python 3 installed locally&lt;/li&gt;
  &lt;li&gt;The &lt;code class="language-markup"&gt;train_FD001.txt&lt;/code&gt; file from the C-MAPSS dataset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it. InfluxDB 3 Core itself is a single binary and brings its own bundled Python for plugins.&lt;/p&gt;

&lt;h2 id="install-influxdb-3-core"&gt;Install InfluxDB 3 Core&lt;/h2&gt;

&lt;p&gt;The quickest path is the official install script, which always pulls the latest release:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;curl -O https://www.influxdata.com/d/install_influxdb3.sh \
  &amp;amp;&amp;amp; sh install_influxdb3.sh core&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When the script finishes, confirm it worked:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 --version&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the &lt;code class="language-markup"&gt;influxdb3&lt;/code&gt; command isn’t found, the installer’s output tells you what to do—usually it’s a matter of sourcing your shell config (for example &lt;code class="language-markup"&gt;source ~/.bashrc or source ~/.zshrc&lt;/code&gt;) so the new binary is on your &lt;code class="language-markup"&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id="docker"&gt;Docker&lt;/h4&gt;

&lt;p&gt;If you’d rather containerize, the Processing Engine is enabled by default in the Docker image (the plugin directory defaults to &lt;code class="language-markup"&gt;/plugins&lt;/code&gt;):&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;docker run -it -p 8181:8181 --name influxdb3-core \
  --volume ~/.influxdb3_data:/var/lib/influxdb3 \
  --volume ~/.influxdb3_plugins:/plugins \
  influxdb:3-core influxdb3 serve \
  --node-id my_host \
  --object-store file \
  --data-dir /var/lib/influxdb3 \
  --plugin-dir /plugins&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the rest of this tutorial we’ll assume the local binary install. The commands translate directly to Docker by prefixing &lt;code class="language-markup"&gt;docker exec -it influxdb3-core&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="start-influxdb-with-the-processing-engine-enabled"&gt;Start InfluxDB with the Processing Engine enabled&lt;/h2&gt;

&lt;p&gt;The Processing Engine activates only when you tell InfluxDB where your plugins live, using the &lt;code class="language-markup"&gt;--plugin-dir&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;First create a directory to hold plugins, then start the server:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;mkdir -p ~/influxdb3/plugins

influxdb3 serve \
  --node-id host01 \
  --object-store file \
  --data-dir ~/.influxdb3 \
  --plugin-dir ~/influxdb3/plugins&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few notes on these flags:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--node-id&lt;/code&gt; is a unique name for this server instance. It forms part of the storage path.&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--object-store file&lt;/code&gt; keeps everything on a local disk under&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--data-dir&lt;/code&gt;. In production you’d point this at S3 or another object store; InfluxDB 3 uses a “diskless” architecture where object storage is the source of truth.&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--plugin-dir&lt;/code&gt; is the directory the engine scans for plugin files. This is the switch that turns the Processing Engine on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leave this server running in its own terminal. Open a second terminal for the remaining commands.&lt;/p&gt;

&lt;p&gt;It’s worth noting that the &lt;code class="language-markup"&gt;influxdb3&lt;/code&gt; binary depends on an adjacent &lt;code class="language-markup"&gt;python/&lt;/code&gt; directory that ships alongside it. If you extracted from a tarball manually, keep the binary and that &lt;code class="language-markup"&gt;python/&lt;/code&gt; folder in the same parent directory and add the parent to your &lt;code class="language-markup"&gt;PATH&lt;/code&gt;, don’t move the binary out on its own, or plugins won’t run.&lt;/p&gt;

&lt;h2 id="create-an-admin-token"&gt;Create an admin token&lt;/h2&gt;

&lt;p&gt;InfluxDB 3 Core uses token authentication. Several operations require an admin token. Create one with the following command:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create token --admin&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This prints a token string once. Copy it somewhere safe; you can’t recover it later (you’d have to regenerate). For convenience in this session, export it:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;export INFLUXDB3_AUTH_TOKEN="paste-your-token-here"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The CLI automatically picks up &lt;code class="language-markup"&gt;INFLUXDB3_AUTH_TOKEN&lt;/code&gt;, so you won’t have to pass &lt;code class="language-markup"&gt;--token&lt;/code&gt; on every command.&lt;/p&gt;

&lt;h2 id="create-a-database"&gt;Create a database&lt;/h2&gt;

&lt;p&gt;Create a database to hold our data:&lt;/p&gt;

&lt;p&gt;&lt;code class="language-markup"&gt;influxdb3 create database engine_fleet&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Verify it exists:&lt;/p&gt;

&lt;p&gt;&lt;code class="language-markup"&gt;influxdb3 show databases&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see &lt;code class="language-markup"&gt;engine_fleet&lt;/code&gt; in the list.&lt;/p&gt;

&lt;h2 id="load-the-dataset-into-influxdb"&gt;Load the dataset into InfluxDB&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.kaggle.com/datasets/bishals098/nasa-turbofan-engine-degradation-simulation"&gt;C-MAPSS&lt;/a&gt; file is a flat, headerless, space-separated table. We need to turn each row into a time series point. There’s one wrinkle worth thinking through: the data has a &lt;code class="language-markup"&gt;time_cycles&lt;/code&gt; counter per engine, not real timestamps. To make this behave like a live stream, we’ll synthesize timestamps by mapping each engine cycle to one second of wall-clock time, anchored to “now minus the engine’s lifetime.” That way recent cycles look recent, which is what a scheduled “look at the last N minutes” plugin expects.&lt;/p&gt;

&lt;p&gt;Here’s a small loader script. It uses the InfluxDB 3 Python client to write line protocol in batches. First install the client into your local Python (this is separate from the engine’s bundled Python), using &lt;a href="https://docs.astral.sh/uv/"&gt;uv&lt;/a&gt; or &lt;a href="https://docs.python.org/3/library/venv.html"&gt;venv&lt;/a&gt; for package management if desired::&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;pip install influxdb3-python pandas&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Save the following as &lt;code class="language-markup"&gt;load_cmapss.py&lt;/code&gt;, adjusting &lt;code class="language-markup"&gt;DATA_FILE&lt;/code&gt; and &lt;code class="language-markup"&gt;TOKEN&lt;/code&gt; as needed:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-python"&gt;# load_cmapss.py
import time
from datetime import datetime, timedelta, timezone

import pandas as pd
from influxdb_client_3 import InfluxDBClient3, Point

# ---- Configuration ----
DATA_FILE = "train_FD001.txt"
HOST = "http://localhost:8181"
DATABASE = "engine_fleet"
TOKEN = "paste-your-admin-token"   # or read from env

# ---- Column names (NASA C-MAPSS layout) ----
index_cols = ["unit_number", "time_cycles"]
setting_cols = ["setting_1", "setting_2", "setting_3"]
sensor_cols = [f"s_{i}" for i in range(1, 22)]
col_names = index_cols + setting_cols + sensor_cols

# ---- Read the space-separated file ----
df = pd.read_csv(DATA_FILE, sep=r"\s+", header=None, names=col_names)
df = df.astype({"unit_number": int, "time_cycles": int})

print(f"Loaded {len(df)} rows across {df['unit_number'].nunique()} engines")

# ---- Synthesize timestamps: 1 cycle == 1 second, anchored so the
#      last cycle of each engine lands at 'now'. ----
now = datetime.now(timezone.utc)
client = InfluxDBClient3(host=HOST, database=DATABASE, token=TOKEN)

points = []
BATCH = 5000

# Per-engine max cycle so we can anchor each engine's final cycle to "now"
max_cycle = df.groupby("unit_number")["time_cycles"].transform("max")
df["ts"] = [
    now - timedelta(seconds=int(mc - tc))
    for mc, tc in zip(max_cycle, df["time_cycles"])
]

for row in df.itertuples(index=False):
    p = (
        Point("sensors")
        .tag("unit_number", str(row.unit_number))
        .field("time_cycles", int(row.time_cycles))
    )
    for c in setting_cols + sensor_cols:
        p = p.field(c, float(getattr(row, c)))
    p = p.time(row.ts)
    points.append(p)

    if len(points) &amp;gt;= BATCH:
        client.write(points)
        points = []

if points:
    client.write(points)

client.close()
print("Done writing sensor data.")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run it:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;python load_cmapss.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few design choices worth calling out:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class="language-markup"&gt;unit_number&lt;/code&gt; is a tag, everything else is a field.&lt;/strong&gt; Tags are indexed and are how you separate one engine’s series from another. Sensor values and the cycle counter are fields.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;We anchor each engine’s final cycle to “now.”&lt;/strong&gt; This means every engine in the fleet looks like it just reached end-of-life, which is convenient for demonstrating alerts. In a real deployment your data already has real timestamps and you’d skip all of this.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Batching matters.&lt;/strong&gt;  Writing 20,000+ points one at a time is slow; batches of a few thousand keep the loader quick.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm the data landed:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query --database engine_fleet \
  "SELECT COUNT(*) FROM sensors"
And take a peek at one engine's recent readings:
influxdb3 query --database engine_fleet \
  "SELECT time, unit_number, time_cycles, s_2, s_4, s_11 \
   FROM sensors WHERE unit_number = '1' \
   ORDER BY time DESC LIMIT 5"&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="an-overview-of-the-plugin-model"&gt;An overview of the plugin model&lt;/h2&gt;

&lt;p&gt;Before writing code, let’s get the mental model straight.&lt;/p&gt;

&lt;p&gt;A plugin is a Python file (or a directory with an &lt;code class="language-markup"&gt;__init__.py&lt;/code&gt; for multi-file plugins) placed in your plugin directory. It defines a function whose signature matches the trigger type:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Data-write plugin: &lt;code class="language-markup"&gt;def process_writes(influxdb3_local, table_batches, args=None):&lt;/code&gt;&amp;lt;/pre&amp;gt;&lt;/li&gt;
  &lt;li&gt;Scheduled plugin: &lt;code class="language-markup"&gt;def process_scheduled_call(influxdb3_local, call_time, args=None):&lt;/code&gt;&amp;lt;/pre&amp;gt;&lt;/li&gt;
  &lt;li&gt;HTTP-request plugin: &lt;code class="language-markup"&gt;def process_request(influxdb3_local, query_parameters, request_headers, request_body, args=None):&lt;/code&gt;&amp;lt;/pre&amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A trigger is the database resource that connects an event to a plugin. You create it with &lt;code class="language-markup"&gt;influxdb3 create trigger&lt;/code&gt;, specifying a &lt;em&gt;trigger spec&lt;/em&gt; that defines when the plugin runs.&lt;/p&gt;

&lt;p&gt;Whatever the type, every plugin receives &lt;code class="language-markup"&gt;influxdb3_local&lt;/code&gt; which is the shared API object that’s your gateway to the database. The methods we’ll use:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;influxdb3_local.query(sql)&lt;/code&gt; - run a SQL query and get results back as a list of dictionaries.&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;influxdb3_local.write(line)&lt;/code&gt; - write a point back into the database, built with the &lt;code class="language-markup"&gt;LineBuilder&lt;/code&gt; helper.&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;influxdb3_local.info(msg)&lt;/code&gt;/ &lt;code class="language-markup"&gt;.warn(msg)&lt;/code&gt; / &lt;code class="language-markup"&gt;.error(msg)&lt;/code&gt; - log to stdout and the system.processing_engine_logs table.&lt;/li&gt;
  &lt;li&gt;The engine also offers an in-memory cache for keeping state between runs (useful for things like tracking a rolling baseline), though we’ll keep our first version stateless.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class="language-markup"&gt;LineBuilder&lt;/code&gt; is the recommended way to construct a point inside a plugin:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-python"&gt;line = LineBuilder("my_table")
line.tag("device", "pump_7")
line.float64_field("value", 42.0)
line.int64_field("count", 3)
influxdb3_local.write(line)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Plugins receive trigger arguments as a &lt;code class="language-markup"&gt;Dict[str, str]&lt;/code&gt; in &lt;code class="language-markup"&gt;args&lt;/code&gt;, which is how we’ll pass tunable thresholds without editing code.&lt;/p&gt;

&lt;h2 id="predictive-maintenance-plugin-logic"&gt;Predictive maintenance plugin logic&lt;/h2&gt;

&lt;p&gt;We need to turn raw sensor readings into a Remaining Useful Life estimate. A full production system might run a trained LSTM or gradient-boosted model, but a tutorial plugin should be transparent and dependency-light, so we’ll use a degradation-index approach that captures the real idea behind RUL prediction without a black box:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Pick the sensors that carry degradation signals. In FD001, several sensors drift steadily as the high-pressure compressor wears. Sensors s_2, s_3, s_4, s_8, s_11, s_13, and s_15 trend upward over an engine’s life; s_7, s_12, s_20, and s_21 trend downward. (Some sensors in FD001 are flat and carry no information—we ignore those.)&lt;/li&gt;
  &lt;li&gt;Normalize each chosen sensor against the healthy-baseline range so they’re comparable, flipping the downward-trending ones so “more degraded” always means “higher.”&lt;/li&gt;
  &lt;li&gt;Average them into a single health index between roughly 0 (factory-fresh) and 1 (failure imminent).&lt;/li&gt;
  &lt;li&gt;Map the index to an RUL estimate. Using the dataset convention that degradation becomes meaningfully predictable in roughly the final 125 cycles, we estimate &lt;code class="language-markup"&gt;RUL ≈ 125 × (1 − health_index)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Alert when the estimated RUL drops below a configurable threshold.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is intentionally simple and explainable. The plugin structure is identical whether the scoring function is ten lines of arithmetic or a 50-megabyte neural network,  you’d just swap the body of &lt;code class="language-markup"&gt;compute_health_index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To normalize, the plugin needs each sensor’s healthy and degraded reference values. Rather than hard-code magic numbers, we’ll derive them once at the top of each run from the fleet itself with the early-life readings approximate “healthy” and the latest readings approximate “degraded.”&lt;/p&gt;

&lt;h2 id="creating-the-plugin"&gt;Creating the plugin&lt;/h2&gt;

&lt;p&gt;Create the plugin file directly in your plugin directory. Save this as &lt;code class="language-markup"&gt;~/influxdb3/plugins/predictive_maintenance.py&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-python"&gt;# predictive_maintenance.py
#
# Scheduled plugin: estimates Remaining Useful Life (RUL) for each engine
# from the most recent sensor readings, writes the estimates back into the
# database, and raises alerts when RUL drops below a threshold.

# Sensors that rise as the engine degrades
RISING = ["s_2", "s_3", "s_4", "s_8", "s_11", "s_13", "s_15"]
# Sensors that fall as the engine degrades
FALLING = ["s_7", "s_12", "s_20", "s_21"]

# Convention from the C-MAPSS literature: degradation becomes meaningfully
# predictable in roughly the final 125 cycles.
MAX_PREDICTABLE_RUL = 125.0

def _safe_float(value, default=0.0):
    try:
        return float(value)
    except (TypeError, ValueError):
        return default

def compute_baselines(influxdb3_local):
    """Derive healthy and degraded reference values for each sensor.

    Healthy  ~ average of the earliest cycles across the fleet.
    Degraded ~ average of the latest cycles across the fleet.
    """
    sensors = RISING + FALLING
    avg_cols = ", ".join([f"AVG({s}) AS {s}" for s in sensors])

    healthy_rows = influxdb3_local.query(
        f"SELECT {avg_cols} FROM sensors WHERE time_cycles = 15"
    )
    degraded_rows = influxdb3_local.query(
        f"SELECT {avg_cols} FROM sensors WHERE time_cycles = 175"
    )

    if not healthy_rows or not degraded_rows:
        return None

    healthy = healthy_rows[0]
    degraded = degraded_rows[0]

    baselines = {}
    for s in sensors:
        lo = _safe_float(healthy.get(s))
        hi = _safe_float(degraded.get(s))
        baselines[s] = (lo, hi)
    return baselines

def normalize(value, lo, hi):
    """Scale a reading to 0..1 between the healthy (lo) and degraded (hi)
    references. Clamps to the [0, 1] range."""
    if hi == lo:
        return 0.0
    frac = (value - lo) / (hi - lo)
    return max(0.0, min(1.0, frac))

def compute_health_index(reading, baselines):
    """Combine the signal-bearing sensors into a single 0..1 degradation
    index. 0 = healthy, 1 = failure imminent."""
    scores = []

    for s in RISING:
        lo, hi = baselines[s]
        scores.append(normalize(_safe_float(reading.get(s)), lo, hi))

    for s in FALLING:
        lo, hi = baselines[s]
        # Falling sensors: degraded value is lower, so invert the scale.
        scores.append(1.0 - normalize(_safe_float(reading.get(s)), hi, lo))

    if not scores:
        return 0.0
    return sum(scores) / len(scores)

def process_scheduled_call(influxdb3_local, call_time, args=None):
    # --- Read tunables from trigger arguments ---
    args = args or {}
    rul_threshold = float(args.get("rul_threshold", "30"))
    lookback = args.get("lookback", "10m")

    influxdb3_local.info(
        f"Predictive maintenance run starting. "
        f"rul_threshold={rul_threshold}, lookback={lookback}"
    )

    # --- Build per-sensor baselines from the fleet ---
    baselines = compute_baselines(influxdb3_local)
    if baselines is None:
        influxdb3_local.warn("Not enough data to compute baselines; skipping run.")
        return

    # --- Get the most recent reading per engine ---
    sensor_select = ", ".join(RISING + FALLING)
    latest = influxdb3_local.query(
        f"""
        SELECT unit_number, time_cycles, {sensor_select}
        FROM sensors
        WHERE time &amp;gt;= now() - INTERVAL '{lookback}'
        ORDER BY time DESC
        """
    )

    if not latest:
        influxdb3_local.warn("No recent sensor data in lookback window.")
        return

    # Keep only the newest row per engine (results are time-desc ordered).
    seen = set()
    newest_per_engine = []
    for row in latest:
        unit = row.get("unit_number")
        if unit not in seen:
            seen.add(unit)
            newest_per_engine.append(row)

    alerts = 0
    for row in newest_per_engine:
        unit = str(row.get("unit_number"))
        cycles = int(_safe_float(row.get("time_cycles")))

        health = compute_health_index(row, baselines)
        est_rul = round(MAX_PREDICTABLE_RUL * (1.0 - health), 1)

        # --- Write the RUL estimate ---
        est = LineBuilder("rul_estimates")
        est.tag("unit_number", unit)
        est.float64_field("health_index", round(health, 4))
        est.float64_field("estimated_rul", est_rul)
        est.int64_field("time_cycles", cycles)
        influxdb3_local.write(est)

        # --- Raise an alert if the engine is in the danger zone ---
        if est_rul = rul_threshold:
            alerts += 1
            severity = "critical" if est_rul = rul_threshold / 2 else "warning"

            alert = LineBuilder("maintenance_alerts")
            alert.tag("unit_number", unit)
            alert.tag("severity", severity)
            alert.float64_field("estimated_rul", est_rul)
            alert.float64_field("health_index", round(health, 4))
            influxdb3_local.write(alert)

            influxdb3_local.warn(
                f"[{severity.upper()}] Engine {unit}: estimated RUL "
                f"{est_rul} cycles (health index {round(health, 2)}). "
                f"Schedule maintenance."
            )

    influxdb3_local.info(
        f"Run complete. Scored {len(newest_per_engine)} engines, "
        f"raised {alerts} alert(s)."
    )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s walk through the important parts.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Baselines from the data help us avoid any magic numbers.&lt;/strong&gt; - &lt;code class="language-markup"&gt;compute_baselines&lt;/code&gt; asks the database for the average sensor values during early life (cycles ≤ 15, “healthy”) and late life (cycles ≥ 175, “degraded”). This adapts automatically to your fleet and means you don’t have to know the absolute scale of s_4 in advance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A single, explainable health index.&lt;/strong&gt; &lt;code class="language-markup"&gt;compute_health_index&lt;/code&gt; normalizes each signal-bearing sensor onto a 0–1 scale and averages them. Rising and falling sensors are both oriented so that 1 always means “more degraded.” This is the piece you’d replace with a trained model in production — the surrounding plumbing stays identical.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Newest reading per engine.&lt;/strong&gt; The query pulls everything in the lookback window ordered newest-first, then we keep the first row we see for each &lt;code class="language-markup"&gt;unit_number&lt;/code&gt;. Because of how we loaded the data (each engine’s last cycle anchored to “now”), the most recent rows are the most degraded.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Writing conclusions back.&lt;/strong&gt; Every engine gets a row in &lt;code class="language-markup"&gt;rul_estimates&lt;/code&gt;. Engines past the threshold also get a row in &lt;code class="language-markup"&gt;maintenance_alerts&lt;/code&gt;, tagged with a &lt;code class="language-markup"&gt;severity&lt;/code&gt; derived from how deep into the danger zone they are, plus a logged warning you’ll see in the server terminal.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configurable via trigger arguments.&lt;/strong&gt; &lt;code class="language-markup"&gt;rul_threshold&lt;/code&gt; and &lt;code class="language-markup"&gt;lookback&lt;/code&gt; come from &lt;code class="language-markup"&gt;args&lt;/code&gt;, so you can retune behavior by recreating the trigger.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="creating-the-trigger"&gt;Creating the trigger&lt;/h2&gt;

&lt;p&gt;Now connect the plugin to a schedule. We’ll run it every minute, with a 30-cycle RUL alert threshold and a 10-minute lookback window:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create trigger \
  --trigger-spec "every:1m" \
  --path "predictive_maintenance.py" \
  --trigger-arguments "rul_threshold=30,lookback=10m" \
  --database engine_fleet \
  pdm_scheduler&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Breaking that down:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--trigger-spec "every:1m"&lt;/code&gt; runs the plugin once a minute. You could also use &lt;code class="language-markup"&gt;cron:&lt;/code&gt; for calendar schedules, for example &lt;code class="language-markup"&gt;cron:0 0 8 * * *&lt;/code&gt; for 8am daily (the format includes seconds).&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--path "predictive_maintenance.py"&lt;/code&gt; is the filename relative to your plugin directory. (For a multi-file plugin you’d point this at the directory containing &lt;code class="language-markup"&gt;__init__.py&lt;/code&gt; instead.)&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;--trigger-arguments&lt;/code&gt; passes our tunables as key=value pairs.&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-markup"&gt;pdm_scheduler&lt;/code&gt; is the trigger’s name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trigger is enabled by default and starts running on the next interval boundary.&lt;/p&gt;

&lt;h2 id="testing-out-the-plugin"&gt;Testing out the plugin&lt;/h2&gt;

&lt;p&gt;Within a minute, the plugin fires. Check the server terminal and you’ll see the &lt;code class="language-markup"&gt;info&lt;/code&gt; and &lt;code class="language-markup"&gt;warn&lt;/code&gt; log lines. Now query what it produced.&lt;/p&gt;

&lt;p&gt;The latest RUL estimates, most-degraded first:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query --database engine_fleet \
  "SELECT unit_number, estimated_rul, health_index, time_cycles \
   FROM rul_estimates \
   ORDER BY time DESC, estimated_rul ASC LIMIT 15"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The maintenance alerts:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query --database engine_fleet \
  "SELECT time, unit_number, severity, estimated_rul, health_index \
   FROM maintenance_alerts \
   ORDER BY time DESC LIMIT 20"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to confirm the plugin is registered and see its file details:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 show plugins&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the engines flagged critical right now:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query --database engine_fleet \
  "SELECT unit_number, estimated_rul FROM maintenance_alerts \
   WHERE severity = 'critical' ORDER BY estimated_rul ASC"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see a spread of RUL estimates across the fleet, with the most-degraded engines surfacing as warnings or criticals.&lt;/p&gt;

&lt;h2 id="inspecting-logs-and-iterating"&gt;Inspecting logs and iterating&lt;/h2&gt;

&lt;p&gt;Plugin logs go both to the server’s stdout and to a system table, which is handy for debugging without scrolling the terminal:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 query --database engine_fleet \
  "SELECT * FROM system.processing_engine_logs ORDER BY time DESC LIMIT 20"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you change the plugin code, you don’t need to recreate the trigger. Edit the file and push the update, preserving the trigger’s configuration and history:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 update trigger \
  --database engine_fleet \
  --trigger-name pdm_scheduler \
  --path "predictive_maintenance.py"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For local development you can also develop a plugin on your own machine and upload it with &lt;code class="language-markup"&gt;--upload&lt;/code&gt; when creating or updating a trigger, which copies the file to the server for you (this requires an admin token). And if you want to dry-run a scheduled plugin without waiting for the interval, there’s &lt;code class="language-markup"&gt;influxdb3 test schedule_plugin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To pause the system without deleting anything:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 disable trigger --database engine_fleet pdm_scheduler
# ...and later...
influxdb3 enable trigger --database engine_fleet pdm_scheduler&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="error-handling"&gt;Error Handling&lt;/h4&gt;

&lt;p&gt;By default, plugin errors are logged and the trigger keeps going. For a critical pipeline you might prefer automatic retries or auto-disable. Set this when creating the trigger with &lt;code class="language-markup"&gt;--error-behavior retry&lt;/code&gt; or &lt;code class="language-markup"&gt;--error-behavior disable&lt;/code&gt; (the default is log).&lt;/p&gt;

&lt;h2 id="what-to-build-next"&gt;What to build next&lt;/h2&gt;

&lt;p&gt;You now have a complete, self-contained predictive maintenance loop running inside InfluxDB 3 
Core. Some natural extensions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Swap in a real model.&lt;/strong&gt; Replace &lt;code class="language-markup"&gt;compute_health_index&lt;/code&gt; with a trained regressor or classifier. Install the library with &lt;code class="language-markup"&gt;influxdb3 install package&lt;/code&gt;, load your serialized model at the top of the plugin, and predict per engine. The trigger, the writes, and the alerts don’t change.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Add a notifier.&lt;/strong&gt; Have the alert branch call an external service like Slack, PagerDuty, email directly from Python. InfluxData also publishes an official notifier plugin you can compose with.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Use the engine’s cache for stateful detection.&lt;/strong&gt; Track a rolling baseline or a per-engine trend slope across runs instead of recomputing fleet baselines each time, using the in-memory cache to persist state between executions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Lower the latency.&lt;/strong&gt; Move from a scheduled trigger to a data-write trigger if you need to react the moment a reading crosses a line.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Browse the official plugin library.&lt;/strong&gt; InfluxData maintains a public repository of plugins (anomaly detection via MAD, threshold/deadman checks, Prophet forecasting, downsampling, and more) that you can reference directly in a trigger with the &lt;code class="language-markup"&gt;gh:&lt;/code&gt; prefix, or copy and adapt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The broader point is the pattern: with the InfluxDB 3 Processing Engine, the intelligence lives in the database, next to the data, reacting as the data moves. For time-series-heavy domains like industrial IoT and predictive maintenance, that proximity is exactly what you want.&lt;/p&gt;
</description>
      <pubDate>Tue, 09 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/predictive-maintenance-plugin-tutorial/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/predictive-maintenance-plugin-tutorial/</guid>
      <category>Developer</category>
      <author>Charles Mahler (InfluxData)</author>
    </item>
    <item>
      <title>Anomaly Detection and Forecasting That Learns From Every Write in InfluxDB</title>
      <description>&lt;p&gt;For many operational time series workloads, machine learning can’t operate in the historical way, where data is compiled once and models are trained offline. Sensor readings, infrastructure metrics, application telemetry, energy data, industrial measurements, and financial ticks all share a basic property: the next datapoint is more useful when the system can respond to it immediately (or at least close to immediately). When a model learns in the same flow that ingests data and reacts to incoming data as it’s written, things like anomaly detection, short-horizon forecasting, and adaptive thresholding all become a lot more useful.&lt;/p&gt;

&lt;p&gt;Enter three new &lt;a href="https://riverml.xyz/dev/"&gt;River&lt;/a&gt;-based plugins for InfluxDB 3:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/influxdata/influxdb3_plugins/tree/main/influxdata/river_anomaly_detector/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=river_plugins_influxdb_3&amp;amp;utm_content=blog"&gt;River Anomaly Detector&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/influxdata/influxdb3_plugins/tree/main/influxdata/river_auto_profiler/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=river_plugins_influxdb_3&amp;amp;utm_content=blog"&gt;River Auto-Profiler&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://github.com/influxdata/influxdb3_plugins/tree/main/influxdata/river_forecaster/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=river_plugins_influxdb_3&amp;amp;utm_content=blog"&gt;River Forecaster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These plugins are built for the InfluxDB 3 Processing Engine and leverage River, a Python library for online machine learning. If you’re unfamiliar with it, the Processing Engine is an embedded Python VM that runs inside InfluxDB 3 and can execute plugin code on writes, schedules, or HTTP requests; it also provides an in-memory cache for stateful applications. For write-triggered plugins, InfluxDB 3 can send batches of data to a plugin as data is flushed through the write-ahead log. River, meanwhile, is designed for models that learn from streaming data incrementally, including anomaly detection, drift detection, and time series forecasting.&lt;/p&gt;

&lt;p&gt;That combination makes InfluxDB 3 and River a perfect match. These plugins bring small, per-series, constantly-updating models directly into the write path, then write the resulting profiles, anomalies, and forecasts back into InfluxDB tables where they can be queried like any other time series data or combined with other triggers and plugins to kick off informed actions. Better yet, they do this all within InfluxDB, eliminating the need for extra infrastructure, servers, and data pipelines to fuel your ML models. In this blog, we’re going to talk about all three new River plugins for InfluxDB, and how they can not only simplify your ML stack, but lead to faster insights through online modeling.&lt;/p&gt;

&lt;h2 id="river-anomaly-detector-multiple-ways-to-detect-problematic-data"&gt;River Anomaly Detector: multiple ways to detect problematic data&lt;/h2&gt;

&lt;p&gt;Let’s start with the River Anomaly Detector.
At a high level, the plugin monitors numeric fields and writes anomaly rows to the table &lt;code class="language-markup"&gt;_anomalies.{source_table}&lt;/code&gt;. It supports rolling Z-score detection, seasonal detection, and &lt;a href="https://riverml.xyz/dev/api/drift/ADWIN/"&gt;adaptive window (ADWIN)&lt;/a&gt;-based drift detection. Each unique combination of table, tags, and field has its own detector state, and models are updated incrementally as new observations arrive.&lt;/p&gt;

&lt;p&gt;The rolling detector tracks an exponentially weighted mean and variance, then flags values that exceed the learned range by a configurable number of standard deviations. The seasonal detector maintains separate time-based buckets, either 24 hour-of-day buckets or 168 hour-of-week buckets, and it compares new values against the bucket that matches the current timestamp. The ADWIN detector watches for changes in the statistical properties of the stream, which is useful when the issue is a behavior shift rather than a single spike.&lt;/p&gt;

&lt;p&gt;Detectors learn from every observation, and you can choose to enable one, two, or all three detector modes, but only the detectors active in the current mode can vote on whether a point is anomalous. This allows you to train the various forms of anomaly detection, then modify your trigger once enough data has been provided to the model. This way, a stream can accumulate enough seasonal history before the seasonal detector is allowed to participate in decisions, and ADWIN can keep learning even when the current mode is using a simpler rolling Z-score path. You don’t even need to specify which detector to use; run the plugin with a minimal trigger such as the following:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 install package river

influxdb3 create trigger \
 --database mydb \
 --plugin-filename gh:influxdata/river_anomaly_detector/river_anomaly_detector.py \
 --trigger-spec "all_tables" \
 anomaly_detector&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With that trigger in place, the plugin starts monitoring numeric fields in all incoming tables. The default behavior is to “auto-tune” and read recommendations from the River Auto Profiling plugin, which we’ll dive into more in the next section.
A typical query against the output might look like this:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-sql"&gt;SELECT
 time,
 host,
 field_name,
 original_value,
 detector_mode,
 rolling_mean,
 rolling_std,
 rolling_deviation,
 rolling_threshold,
 seasonal_bucket,
 drift_detected
FROM "_anomalies.cpu"
ORDER BY time DESC
LIMIT 20;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That output is deliberately detailed: you get the original value, the active detector mode, rolling statistics, seasonal statistics when available, and ADWIN drift information. The plugin only writes rows where a datapoint is determined to be an anomaly, so the anomaly table is an event stream rather than a full copy of the source data.&lt;/p&gt;

&lt;p&gt;For a stable metric, the detector may run with a lower Z-score threshold because small deviations are meaningful. For a noisy metric, it may use a higher threshold to avoid producing noise. For a metric with a strong weekly pattern, seasonal buckets can separate “expected at 2 p.m. on Monday” from “expected in general.” For a metric that is drifting, ADWIN can participate so the detector can respond to changes in the stream rather than treating every shift as a one-off outlier.&lt;/p&gt;

&lt;p&gt;You can also make the mode explicit. For example, if you only care about a specific table and you know it has strong daily or weekly seasonality on a couple fields you want to monitor, you can specify this and force the plugin to only use seasonal detection:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create trigger \
 --database mydb \
 --plugin-filename gh:influxdata/river_anomaly_detector/river_anomaly_detector.py \
 --trigger-spec "table:cpu" \
 --trigger-arguments \
   'include_fields=temperature humidity' \
   'rolling_std_threshold=3.0' \
   'enable_seasonal=true' \
 anomaly_detector_cpu&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The detector can encode understanding in the database itself, close to the data, while still leaving room for explicit configuration when you know exactly what you want. Whether you want adaptive detection, rolling Z-scores, seasonal detection, or some combination of the three, the River Anomaly Detector plugin can make it happen, and it’s truly as simple as defining the tables and fields you want it to operate on.&lt;/p&gt;

&lt;h2 id="river-auto-profiler-the-control-plane-for-per-series-tuning"&gt;River Auto-Profiler: the control plane for per-series tuning&lt;/h2&gt;

&lt;p&gt;The Auto-Profiler is the least flashy of the three plugins, but it is the one that makes the anomaly detector more practical at scale.&lt;/p&gt;

&lt;p&gt;A static threshold is easy to understand and easy to deploy. It is also usually wrong somewhere. A metric that barely moves, a metric with high variance, a metric with a weekly pattern, and a metric undergoing a slow drift should not all use the same anomaly detection settings. You can tune each field by hand, but that does not scale well when your schema grows or when the behavior of a series changes over time.&lt;/p&gt;

&lt;p&gt;The Auto-Profiler addresses that by incrementally profiling each numeric series and writing recommendations to &lt;code class="language-markup"&gt;_meta.series_profiles&lt;/code&gt;. It tracks exponentially weighted mean and variance, skewness, &lt;a href="https://en.wikipedia.org/wiki/Kurtosis"&gt;kurtosis&lt;/a&gt;, write interval, and seasonal variance buckets. After a short calibration phase, it writes profile snapshots that include a pattern label, recommended detector mode, threshold, fading factors, seasonality strength, trend strength, and maturity flags.&lt;/p&gt;

&lt;p&gt;Creating the trigger is intentionally simple:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create trigger \
 --database mydb \
 --plugin-filename gh:influxdata/river_auto_profiler/river_auto_profiler.py \
 --trigger-spec "all_tables" \
 auto_profiler&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you can inspect the current profile state:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-sql"&gt;SELECT
 time,
 source_table,
 host,
 field_name,
 observations,
 pattern_label,
 recommended_detector_mode,
 recommended_threshold,
 recommended_fading_factor,
 seasonality_strength,
 trend_strength,
 profile_mature,
 seasonality_ready
FROM "_meta.series_profiles"
ORDER BY time DESC
LIMIT 20;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The classifier is intentionally transparent. It labels streams as stable, noisy, trending, seasonal, or bursty and maps those labels to detector modes such as &lt;code class="language-markup"&gt;zscore_low&lt;/code&gt;, &lt;code class="language-markup"&gt;zscore_high&lt;/code&gt;, &lt;code class="language-markup"&gt;zscore_adaptive&lt;/code&gt;, &lt;code class="language-markup"&gt;zscore_conservative seasonal&lt;/code&gt;, or &lt;code class="language-markup"&gt;zscore_conservative adwin&lt;/code&gt;. Seasonality detection uses hourly or weekly variance buckets, and trend detection compares fast and slow exponentially weighted means.&lt;/p&gt;

&lt;p&gt;That transparency is useful. If a profile says a series is seasonal, you can look at the &lt;code class="language-markup"&gt;seasonality_strength&lt;/code&gt; and &lt;code class="language-markup"&gt;seasonal_buckets_filled&lt;/code&gt; fields. If it says a series is trending, you can inspect &lt;code class="language-markup"&gt;trend_strength&lt;/code&gt;. If the profile is not mature yet, downstream consumers can fall back to safer defaults.&lt;/p&gt;

&lt;p&gt;The Auto-Profiler also tunes thresholds using observed exceedance behavior. It tracks how often observations fall outside &lt;code class="language-markup"&gt;mean ± threshold × std&lt;/code&gt; and adjusts the threshold toward an approximate target anomaly rate, with bounds to avoid unbounded sensitivity changes. That does not make anomaly detection “automatic” in the magical sense. It makes it adaptive in the operational sense: the system can use what it has learned about each series to pick a more appropriate starting point.&lt;/p&gt;

&lt;p&gt;The most important integration is with the anomaly detector. With both plugins deployed, the profiler writes per-series recommendations, and the anomaly detector consumes those recommendations to adapt to your data, weed out anomalies, and minimize noise.&lt;/p&gt;

&lt;h2 id="river-forecaster-short-horizon-forecasts-from-the-write-stream"&gt;River Forecaster: short-horizon forecasts from the write stream&lt;/h2&gt;

&lt;p&gt;The River Forecaster takes the same online-learning pattern and applies it to forecasting.
The plugin uses River’s &lt;a href="https://riverml.xyz/dev/api/time-series/SNARIMAX/"&gt;SNARIMAX&lt;/a&gt; model, an online &lt;a href="https://www.ibm.com/think/topics/arima-model"&gt;ARIMA&lt;/a&gt;-style model, to learn from incoming values and periodically write multi-step forecasts to &lt;code class="language-markup"&gt;_forecasts.{source_table}&lt;/code&gt;. Like the anomaly detector, it keeps a separate model per table/tag/field series. Unlike the anomaly detector, it requires explicit table selection through &lt;code class="language-markup"&gt;include_tables&lt;/code&gt;, which is a necessary guardrail for forecast cardinality.&lt;/p&gt;

&lt;p&gt;A trigger for the forecasting plugin might look like this:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;influxdb3 create trigger \
 --database mydb \
 --plugin-filename gh:influxdata/river_forecaster/river_forecaster.py \
 --trigger-spec "all_tables" \
 --trigger-arguments \
   "include_tables=system_cpu system_memory" \
   "include_fields=idle used available" \
   "max_series=100" \
   "default_horizon=24" \
   "log_forecasts=true" \
 forecaster&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By default, the model waits for a warm-up period before producing forecasts. The forecast horizon is also derived from the stream. The plugin tracks each model’s write interval and uses it to choose how many future steps are needed to cover a target forecast window, which defaults to one hour. If a series is written every 10 seconds, the forecast horizon can be much longer than a series written every five minutes, because the time window is the same, but the step size is different.&lt;/p&gt;

&lt;p&gt;You can query forecasts like this:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-sql"&gt;SELECT
 time,
 host,
 field_name,
 horizon_step,
 forecast_value,
 horizon_total,
 observations
FROM "_forecasts.system_cpu"
ORDER BY time DESC
LIMIT 12;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each forecast row receives a future timestamp based on the last observed timestamp plus &lt;code class="language-markup"&gt;horizon_step * write_interval_seconds&lt;/code&gt;. The output includes the forecasted value, the step number, total horizon length, and the number of observations the model has learned from.&lt;/p&gt;

&lt;p&gt;The forecaster also self-throttles per model. It produces a forecast, stores those predictions in memory, and then compares them step by step against incoming actuals. A new forecast is produced once the previous forecast horizon has been consumed, so evaluation covers the full horizon rather than a partial subset.&lt;/p&gt;

&lt;p&gt;That makes the plugin useful for near-term operational questions. For the example above (forecasting CPU and system memory utilization), these questions might be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Is memory usage expected to cross a threshold in the next hour?&lt;/li&gt;
  &lt;li&gt;Is a sensor trending toward a range that usually precedes maintenance?&lt;/li&gt;
  &lt;li&gt;Is the current CPU-idle forecast consistent with what the anomaly detector is seeing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not the only forecasting questions you might ask of time series data, but they are the kind that fit well in a write-triggered architecture.&lt;/p&gt;

&lt;h2 id="using-the-river-plugins-with-influxdb"&gt;Using the River plugins with InfluxDB&lt;/h2&gt;

&lt;p&gt;With the simplicity of InfluxDB 3’s embedded Processing Engine, getting started with notoriously difficult or complicated ML tasks is now simpler, faster, and easier than ever. For all three of these River ML plugins, you can view the code and README files within the &lt;a href="https://github.com/influxdata/influxdb3_plugins/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=river_plugins_influxdb_3&amp;amp;utm_content=blog"&gt;InfluxDB 3 plugin repository&lt;/a&gt;, with full documentation for configuration and recommended use. Installing them is as simple as defining and starting the triggers within the processing engine.&lt;/p&gt;

&lt;p&gt;Make sure you’re intentional about which tables and fields you monitor. You should think about cold starts, profile maturity, and whether a given field has enough regularity for short-horizon forecasting. These questions exist whenever you’re deploying ML techniques on data—this isn’t magic.&lt;/p&gt;

&lt;p&gt;Once you have the plugins up and running, everything should work seamlessly as described above, adapting and learning from the data written to your tables. All three plugins’ outputs remain in InfluxDB. Profiles are written to  &lt;code class="language-markup"&gt;_meta.series_profiles&lt;/code&gt;. Any detected anomalies are written to &lt;code class="language-markup"&gt;_anomalies.{source_table}&lt;/code&gt;. Forecasts are written to &lt;code class="language-markup"&gt;_forecasts.{source_table}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means the operational burden is small, and you can query profiles, anomalies, forecasts, and raw data with SQL. You can visualize your River ML-generated data in dashboards alongside the raw and processed data you’ve written into InfluxDB, join different datasets together, and inspect behavior, anomalies, and forecasts without needing to involve any other services or platforms. You don’t need additional hardware or pipelines or self-written plugins to extract your time series data into an offline system for ML. It may just be the easiest way to leverage your time series data for machine learning out there. By embedding these plugins within InfluxDB, your training workflows and ML insights can now live closer to the raw data than ever before.&lt;/p&gt;
</description>
      <pubDate>Thu, 04 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/river-plugins-influxdb-3/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/river-plugins-influxdb-3/</guid>
      <category>Developer</category>
      <author>Cole Bowden, Ryan Nelson (InfluxData)</author>
    </item>
    <item>
      <title>6 Signs Your Historian Renewal Should Be a Modernization Conversation</title>
      <description>&lt;p&gt;Renewal notices don’t arrive with a subject line that says “modernization conversation enclosed.” They show up as a line item in procurement, usually with a larger number than the previous year. Most teams sign and move on.&lt;/p&gt;

&lt;p&gt;The ones that pause tend to find the renewal moment is a useful forcing function, not to rip out the historian, but to ask whether the current architecture can support what the business needs over the next three years.&lt;/p&gt;

&lt;p&gt;If any of the following sounds familiar, that audit is worth running before you sign.&lt;/p&gt;

&lt;h2 id="sign-1-your-renewal-quote-is-higher-and-so-is-your-tag-count"&gt;Sign 1: Your renewal quote is higher, and so is your tag count&lt;/h2&gt;

&lt;p&gt;The math used to work. When the historian was first deployed, per-tag pricing was predictable. You knew the count, you knew the cost, and the line item made sense against the operational value it delivered. However, that equation breaks down as instrumentation expands.&lt;/p&gt;

&lt;p&gt;For example, AVEVA PI customers are seeing renewal pressure even as their tag counts increase. Some organizations have seen AVEVA pricing increase 20-40% over the last 18 months.
That creates the wrong incentive: collect less data, sample less often, or pay more for the visibility the business now needs.&lt;/p&gt;

&lt;p&gt;There’s a compounding factor that often goes unexamined. Deprecated tags, from decommissioned equipment, retired sensors, or replaced instrumentation, still count toward your license. The pricing model doesn’t distinguish between a tag that’s actively collecting at 1Hz and one that’s been dark for two years. In industries where equipment turns over regularly, paying full price for data you no longer collect is an inevitability. The tag footprint grows in both directions: new assets add tags at the front, old ones don’t shed them at the back.&lt;/p&gt;

&lt;p&gt;If your procurement team is asking why the historian line item keeps growing while your OT team can’t fully instrument what it needs to, the commercial model has already stopped working for you.&lt;/p&gt;

&lt;h2 id="sign-2-your-data-science-team-is-still-waiting-for-that-export"&gt;Sign 2: Your data science team is still waiting for that export&lt;/h2&gt;

&lt;p&gt;This appears consistently across industrial organizations. Analytics and AI initiatives get funded, data scientists are hired, and then they spend the first few months writing tickets to the OT team asking for historian exports.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PI Vision and PI DataLink weren’t built for Python, pandas, or Databricks.&lt;/li&gt;
  &lt;li&gt;Getting data out requires proprietary connectors, manual exports, or PI Web API integrations that take weeks to stand up.&lt;/li&gt;
  &lt;li&gt;By the time the data reaches the ML pipeline, it’s stale, downsampled, or stripped of the context it needs to be useful.&lt;/li&gt;
  &lt;li&gt;The data science team that was supposed to be building predictive maintenance models is still, months later, doing data plumbing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s a structural issue behind the export problem. Historians were built to store industrial tags, usually SCADA or PLC-process information, mapped to an ISA-95 hierarchy. What they weren’t designed to do is store metadata and context alongside raw industrial signals. That gap matters more as analytics mature.&lt;/p&gt;

&lt;p&gt;Enriching SCADA data with MES data about production shifts, ERP data about batches and stock levels, or equipment metadata for grouping by manufacturing type requires a platform that treats context as a first-class citizen alongside telemetry. Without it, even a well-delivered data export produces a one-dimensional analysis. You see what happened, but you don’t understand why.&lt;/p&gt;

&lt;p&gt;If “how do we give the analytics team access to OT data” is still an open question, you’re looking at a historian problem.&lt;/p&gt;

&lt;h2 id="sign-3-a-new-workload-just-got-bounced-back-to-you"&gt;Sign 3: A new workload just got bounced back to you&lt;/h2&gt;

&lt;p&gt;Someone in the business asked you to support something the historian wasn’t built for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Cell-level monitoring for a new BESS installation at 1Hz, when your historian’s default polling interval is 5-15 minutes.&lt;/li&gt;
  &lt;li&gt;Vibration analysis on rotating equipment, where sub-second resolution is required, and tag economics become punishing fast.&lt;/li&gt;
  &lt;li&gt;A new greenfield facility where the capital plan assumes modern, cloud-connected data infrastructure.&lt;/li&gt;
  &lt;li&gt;A real-time anomaly detection model that needs data before the dashboard refresh cycle catches it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When your answer has to be “the historian can’t do that at that frequency” or “it can, but here’s what the additional tags will cost,” the conversation has changed. The workloads the business needs have outpaced what the platform was sized for.&lt;/p&gt;

&lt;p&gt;The throughput problem has a storage dimension too, and it’s the one that tends to catch teams off-guard. Historians weren’t built for indefinite storage of high-volume, high-frequency data. Industry 4.0 use cases, including predictive maintenance models, asset warranty tracking, and long-range efficiency analysis, need data stored over years, not rolling windows. When you try to do that in a historian, storage costs compound quickly, and data accessibility often degrades. The business case for those use cases depends on querying three years of sensor data quickly. A historian scoped for operational visibility doesn’t make that easy.&lt;/p&gt;

&lt;h2 id="sign-4-every-plant-is-an-island"&gt;Sign 4: Every plant is an island&lt;/h2&gt;

&lt;p&gt;Your historian keeps the plant running. It doesn’t know the fleet exists.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Cross-site benchmarking requires custom middleware that someone has to build, maintain, and eventually explain to their replacement.&lt;/li&gt;
  &lt;li&gt;Fleet-level analysis comparing performance across sites means extracting and normalizing data from multiple historian instances with inconsistent tag naming.&lt;/li&gt;
  &lt;li&gt;Centralized reporting for leadership involves someone in OT running manual aggregation every Monday.&lt;/li&gt;
  &lt;li&gt;Each new site gets the same plant-centric architecture, compounding the cross-site problem with every expansion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plant-island problem goes deeper than data access. Each site typically operates by its own data standard, with tag naming conventions, unit definitions, and hierarchy structures that made sense locally but weren’t designed for comparison. Cross-plant analysis requires a standardization layer built and maintained on top of the historian, and that layer tends to be fragile, undocumented, and owned by whoever happened to build it.&lt;/p&gt;

&lt;p&gt;There’s also an architectural concern that digital transformation teams are raising with increasing frequency: reaching back into plant networks to pull data from individual historian instances creates bandwidth and security risk. The better pattern is a single, standardized interface at the enterprise layer, one that aggregates and normalizes across sites without requiring anyone to access operational technology networks to run a comparison report.&lt;/p&gt;

&lt;h2 id="sign-5-the-platform-is-a-closed-system-and-thats-becoming-a-problem"&gt;Sign 5: The platform is a closed system, and that’s becoming a problem&lt;/h2&gt;
&lt;p&gt;Historians accumulate dependencies as much as they accumulate data. The proprietary architecture that made them reliable for single-site operational visibility also makes them difficult to extend, integrate, or evolve.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Integrations are built through proprietary SDKs and connectors. When a vendor discontinues one, the integration breaks.&lt;/li&gt;
  &lt;li&gt;The platform’s data model isn’t designed to connect with open standards like SQL, JDBC, or ODBC without significant middleware investment.&lt;/li&gt;
  &lt;li&gt;Every new capability, whether a new visualization layer, analytics integration, or edge deployment pattern, requires either a vendor-supplied solution or a custom workaround.&lt;/li&gt;
  &lt;li&gt;Legacy .NET dependencies constrain where and how the platform can be deployed, and the team managing it today is working from a roadmap they don’t control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where vendor lock-in stops being an abstract concern and becomes an operational one. Every renewal locks in the architecture for another cycle. Teams that don’t own their data layer, can’t control their integration strategy, and can’t switch tools without rebuilding from scratch are paying for a constraint, not just a platform.&lt;/p&gt;

&lt;p&gt;Open standards, SQL, JDBC, ODBC, and common client libraries, exist precisely to avoid this. They let teams retain skills, use the right tool for the right job, and avoid designing in a vendor dependency that becomes painful at exactly the moment of renewal.&lt;/p&gt;

&lt;h2 id="sign-6-historian-limitations-shows-up-in-every-initiatives-risk-log"&gt;Sign 6: “Historian limitations” shows up in every initiative’s risk log&lt;/h2&gt;

&lt;p&gt;This is the one that tends to crystallize things for digital transformation and operations leaders. At some point, the pattern becomes visible:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;BESS monitoring is blocked by polling intervals.&lt;/li&gt;
  &lt;li&gt;The ML pipeline is blocked by proprietary data access.&lt;/li&gt;
  &lt;li&gt;Cloud migration is complicated by the on-prem historian footprint.&lt;/li&gt;
  &lt;li&gt;Edge data collection for remote assets requires custom workarounds.&lt;/li&gt;
  &lt;li&gt;Cross-site analytics is deferred indefinitely, pending a middleware project that never gets resourced.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the historian appears in the constraints column on enough project charters, teams stop treating it as a given and start treating it as something to engineer around. That shift in framing is usually the start of a different conversation.&lt;/p&gt;

&lt;h2 id="what-to-do-about-it-before-signing-a-contract"&gt;What to do about it, before signing a contract&lt;/h2&gt;

&lt;p&gt;None of this necessarily means replacing the historian. Most industrial teams that modernize their data infrastructure augment their deployment rather than pursuing an immediate rip-and-replace.&lt;/p&gt;

&lt;p&gt;The pattern that has worked for organizations like Terega and SP Energy Networks is to deploy InfluxDB alongside AVEVA PI. In those deployments, the historian handles legacy SCADA historization, GxP data, and established PI Vision workflows, while InfluxDB takes on high-frequency BESS monitoring, predictive maintenance pipelines, new greenfield sites, and cross-site fleet analytics.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compute-based pricing means unlimited tags, with no per-sensor cost penalty.&lt;/li&gt;
  &lt;li&gt;Native SQL, 14 client libraries, and direct Grafana, Power BI, and Python integration with no proprietary SDK.&lt;/li&gt;
  &lt;li&gt;InfluxDB 3 Core runs at the edge; Enterprise or Cloud serves as the central hub, with one SQL interface across both.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For organizations facing a significant renewal, planning a new facility, or actively evaluating a full exit from the historian architecture, the path is a complete replacement. This includes InfluxDB for time series storage, and Litmus Edge or Highbyte for industrial connectivity and asset modeling.&lt;/p&gt;

&lt;p&gt;Terega, the French gas network operator, deployed InfluxDB alongside their historian when they were heading toward seven-figure annual OSI PI costs. They now collect 20x more data at 50% lower cost. SP Energy Networks became the first UK utility to receive Ofgem approval for a cloud-hosted historian, running on InfluxDB. That decision has since opened the door for other regulated UK operators to evaluate the same path.&lt;/p&gt;

&lt;p&gt;The renewal notice is a useful moment. Use it to ask whether the current architecture can carry what the business needs from it next, and what it would take to find out.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://www.influxdata.com/products/influxdb/?utm_source=website&amp;amp;utm_medium=direct&amp;amp;utm_campaign=modernize_your_historian_6_signs&amp;amp;utm_content=blog&amp;amp;utm_content=blog"&gt;Get InfluxDB free&lt;/a&gt;] InfluxDB 3 Core is open source and available now. Deploy at the edge in minutes. No per-tag pricing. Native SQL. Direct Grafana and Power BI integration.&lt;/p&gt;
</description>
      <pubDate>Mon, 01 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/modernize-your-historian-6-signs/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/modernize-your-historian-6-signs/</guid>
      <category>Developer</category>
      <author>Ryan Nelson (InfluxData)</author>
    </item>
    <item>
      <title>InfluxDB 3 MCP Server v1.3.0: AI Access to Time Series Data</title>
      <description>&lt;p&gt;&lt;em&gt;A more reliable agent that learns your schema, queries your data, and investigates alerts - that’s what’s possible with this release of our MCP server v1.3.0.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;This release enhances the InfluxDB 3 MCP server—which already allows AI agents like Claude and ChatGPT to read from and write to your InfluxDB 3 instance using natural language—with key dependability improvements, including protocol compliance tests, integration tests, and a properly scoped npm package.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;What it is&lt;/strong&gt;: an MCP server that exposes InfluxDB 3 tools, including query, write, schema discovery, database management, and token management, to any MCP-compatible client.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;What changed in 1.3.0&lt;/strong&gt;: test coverage, CI, the updated MCP SDK (1.27.1), &lt;code class="language-markup"&gt;@influxdata/influxdb3-client&lt;/code&gt; 1.4.0, a Node 20.11+ baseline, and safer error responses.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt;: &lt;code class="language-markup"&gt;npx -y @influxdata/influxdb3-mcp-server&lt;/code&gt;. No clone, no build.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;See it work&lt;/strong&gt;: we ran an agent investigation against the &lt;a href="https://github.com/influxdata/influxdb3-ref-bess/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;influxdb3-ref-bess &lt;/a&gt;reference architecture with prompts for schema discovery, current state, forcing a thermal runaway alert, and pivoting back to readings.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Where to get it&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/@influxdata/influxdb3-mcp-server"&gt;npm&lt;/a&gt; · &lt;a href="https://hub.docker.com/r/influxdata/influxdb3-mcp-server"&gt;Docker&lt;/a&gt; · &lt;a href="https://github.com/influxdata/influxdb3_mcp_server"&gt;GitHub&lt;/a&gt; · &lt;a href="https://github.com/influxdata/influxdb3_mcp_server/blob/main/CHANGELOG.md"&gt;CHANGELOG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="what-is-the-influxdb-3-mcp-server"&gt;What is the InfluxDB 3 MCP server?&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol is an open standard for connecting AI agents to external tools and data. Our MCP server is the official InfluxData implementation: it runs locally over stdio, accepts a connection from your MCP client (Claude Desktop, Claude Code, OpenAI Codex, Cursor, and others), and exposes InfluxDB 3 as a set of tools the agent can call on your behalf.&lt;/p&gt;

&lt;p&gt;It works across all InfluxDB 3 editions—Core, Enterprise, Cloud Dedicated, Cloud Serverless, and Clustered—with tools adapted to each product. For example, admin token management is only available on Core and Enterprise; bucket retention is a Cloud Serverless concern.&lt;/p&gt;

&lt;p&gt;For background and the original tool tour, see our previous posts: &lt;a href="https://www.influxdata.com/blog/influxdb-mcp-server/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;Introducing the InfluxDB 3 MCP server&lt;/a&gt; and &lt;a href="https://www.influxdata.com/blog/influxdb-3-mcp-server-claude/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;Building with the InfluxDB 3 MCP server &amp;amp; Claude&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="whats-new-in-v130"&gt;What’s new in v1.3.0?&lt;/h2&gt;

&lt;p&gt;This release makes the MCP server safer and more dependable:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Scoped npm package&lt;/strong&gt;. The official server is now &lt;code class="language-markup"&gt;@influxdata/influxdb3-mcp-server&lt;/code&gt; (the unscoped &lt;code class="language-markup"&gt;influxdb-mcp-server&lt;/code&gt; on npm is an unrelated community project); always use the scoped name.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Protocol-compliance test suite&lt;/strong&gt;. Verifies server startup, the MCP handshake, and tool/resource/prompt registration.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration tests against Core and Cloud Serverless&lt;/strong&gt;. A first set covering &lt;code class="language-markup"&gt;health_check&lt;/code&gt;, &lt;code class="language-markup"&gt;list_databases&lt;/code&gt;, and &lt;code class="language-markup"&gt;execute_query&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;__Server-level errors now set &lt;code class="language-markup"&gt;isError__: true&lt;/code&gt;, matching handler-level responses. MCP clients see failures as failures, not as empty success responses.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Plain-text error responses (HTTP 500) from Core now pass through to the MCP client with their original message,&lt;/strong&gt; instead of being replaced by a generic “Internal Server Error.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MCP SDK 1.12 → 1.27.1&lt;/strong&gt; and &lt;code class="language-markup"&gt;@influxdata/influxdb3-client&lt;/code&gt; &lt;strong&gt;1.1 → 1.4.0&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node 20.11 minimum&lt;/strong&gt;: Node 18 reached end of life.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="how-do-i-install-the-mcp-server-for-influxdb-3-core"&gt;How do I install the MCP Server for InfluxDB 3 Core?&lt;/h2&gt;

&lt;p&gt;If you haven’t already installed Core and created an admin token, follow the &lt;a href="https://docs.influxdata.com/influxdb3/core/get-started/setup/"&gt;Set up Core&lt;/a&gt; guide (you’ll be running within 5 minutes).&lt;/p&gt;

&lt;p&gt;The following example uses &lt;code class="language-markup"&gt;npx&lt;/code&gt;, which is the easiest way to get started.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Add the server to your MCP client config&lt;/strong&gt;. For Claude Desktop, edit &lt;code class="language-markup"&gt;claude_desktop_config.json&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class=""&gt;&lt;code class="language-json"&gt;{
  "mcpServers": {
    "influxdb": {
      "command": "npx",
      "args": ["-y", "@influxdata/influxdb3-mcp-server"],
      "env": {
        "INFLUX_DB_INSTANCE_URL": "http://localhost:8181/",
        "INFLUX_DB_TOKEN": "YOUR_ADMIN_TOKEN",
        "INFLUX_DB_PRODUCT_TYPE": "core"
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Restart Claude Desktop&lt;/strong&gt;. The first launch downloads the package; subsequent launches are instant.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sanity-check&lt;/strong&gt;. Open a new chat and ask: “Use the InfluxDB tools to list my databases.”
Claude should call the &lt;code class="language-markup"&gt;list_databases&lt;/code&gt; tool and return whatever’s on your instance.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id="other-mcp-clients"&gt;Other MCP Clients&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://github.com/influxdata/influxdb3_mcp_server#readme"&gt;README&lt;/a&gt; includes specific config-file snippets for other MCP clients.&lt;/p&gt;

&lt;p&gt;Prefer Docker? The v1.3.0 image is on Docker Hub at &lt;a href="https://hub.docker.com/r/influxdata/influxdb3-mcp-server"&gt;influxdata/influxdb3-mcp-server&lt;/a&gt;. Our &lt;a href="https://www.influxdata.com/blog/influxdb-3-mcp-server-claude/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;January walkthrough&lt;/a&gt; covers the Docker-based setup in detail.&lt;/p&gt;

&lt;h2 id="how-do-i-install-the-mcp-server-for-influxdb-3-enterprise"&gt;How do I install the MCP Server for InfluxDB 3 Enterprise?&lt;/h2&gt;

&lt;p&gt;Enterprise uses the same configuration shape, just replace the environment variable values:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-json"&gt;{
  "mcpServers": {
    "influxdb": {
      "command": "npx",
      "args": ["-y", "@influxdata/influxdb3-mcp-server"],
      "env": {
        "INFLUX_DB_INSTANCE_URL": "https://your-enterprise-host/",
        "INFLUX_DB_TOKEN": "YOUR_ADMIN_TOKEN",
        "INFLUX_DB_PRODUCT_TYPE": "enterprise"
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enterprise adds licensed multi-node and read/write replica features, but to the MCP client, the tools look the same as Core. The &lt;a href="https://docs.influxdata.com/influxdb3/enterprise/install/"&gt;Enterprise install guide&lt;/a&gt; covers licensing and provisioning.&lt;/p&gt;

&lt;h4 id="cloud-variants"&gt;Cloud Variants&lt;/h4&gt;

&lt;p&gt;Cloud Serverless uses the same three-variable shape, just swap the URL and set &lt;code class="language-markup"&gt;INFLUX_DB_PRODUCT_TYPE=cloud-serverless&lt;/code&gt;. Cloud Dedicated and Clustered are slightly different: Cloud Dedicated takes a cluster ID instead of a host URL, and both support an optional separate management token. See the exact recipe for each in the MCP server &lt;a href="https://github.com/influxdata/influxdb3_mcp_server#readme"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="try-it-against-a-real-running-system"&gt;Try it against a real running system&lt;/h2&gt;

&lt;p&gt;Run MCP against live data in one of our reference architecture demos to simulate a real environment. The ref arch demos run on InfluxDB 3 Enterprise by default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/influxdata/influxdb3-ref-bess/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;influxdb3-ref-bess&lt;/a&gt; is our reference architecture for Battery Energy Storage Systems on InfluxDB 3: a simulator writing 768 cells across 4 packs at ~2,000 points per second, in-database Python plugins performing thermal-runaway detection and daily SoH rollups, and a control-room UI. &lt;code class="language-markup"&gt;make demo&lt;/code&gt; brings the whole thing up in about two minutes.&lt;/p&gt;

&lt;p&gt;Point your MCP server’s &lt;code class="language-markup"&gt;INFLUX_DB_INSTANCE_URL&lt;/code&gt; and &lt;code class="language-markup"&gt;INFLUX_DB_TOKEN&lt;/code&gt; at the ref-arch instance, and set &lt;code class="language-markup"&gt;INFLUX_DB_PRODUCT_TYPE=enterprise&lt;/code&gt;. An agent now has a real plant to investigate. Here’s a session we ran in Claude Code.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Orient&lt;/strong&gt;.&lt;/p&gt;

    &lt;p&gt;“I have InfluxDB 3 running locally with a BESS reference simulator writing data into it. List the databases on this instance, then, for the &lt;code class="language-markup"&gt;bess&lt;/code&gt; database, show me which measurements exist and the schema of each.”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent chose the tools and made seven calls: &lt;code class="language-markup"&gt;list_databases&lt;/code&gt;, then &lt;code class="language-markup"&gt;get_measurements&lt;/code&gt; and &lt;code class="language-markup"&gt;get_measurement_schema&lt;/code&gt; once per table. It returned this summary: &lt;code class="language-markup"&gt;cell_readings&lt;/code&gt; (per-cell voltage and temperature), &lt;code class="language-markup"&gt;pack_readings&lt;/code&gt; (pack-level current, SoC, SoH), &lt;code class="language-markup"&gt;inverter_readings&lt;/code&gt; (site power), and &lt;code class="language-markup"&gt;alerts&lt;/code&gt; (an event stream written by an in-database plugin when a cell crosses a threshold).&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Current state of the plant&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;“Show me the current state of each pack: the most recent &lt;code class="language-markup"&gt;current_a&lt;/code&gt;, SoC, and SoH per &lt;code class="language-markup"&gt;pack_id&lt;/code&gt; from &lt;code class="language-markup"&gt;pack_readings&lt;/code&gt;.”&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;pack     current_a   SoC      SoH       as of
pack-0   -80.0       53.0%    98.1%     14:09:36
pack-1   -80.0       61.8%    97.9%     14:09:36
pack-2   -80.0       63.8%    98.1%     14:09:36
pack-3   -80.0       60.8%    98.0%     14:09:36&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The agent used &lt;code class="language-markup"&gt;DISTINCT ON (pack_id) ... ORDER BY pack_id, time DESC&lt;/code&gt;, the DataFusion/Postgres idiom for “latest row per group,” which is typically cheaper than the more portable &lt;code class="language-markup"&gt;ROW_NUMBER()&lt;/code&gt; window-function pattern. It picked the SQL from the schema it discovered in prompt 1. The agent also flagged a simulator bug that we hadn’t asked about: all four packs were reporting the same current. Real BESS sites rarely dispatch evenly due to SoC balancing, thermal derating, and inverter routing.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Investigate alerts&lt;/strong&gt;.&lt;/p&gt;

    &lt;p&gt;“Any alerts in the last 15 minutes in the &lt;code class="language-markup"&gt;alerts&lt;/code&gt; table? If so, find the most recent alert’s &lt;code class="language-markup"&gt;pack_id&lt;/code&gt; and timestamp, then show me the &lt;code class="language-markup"&gt;cell_readings&lt;/code&gt; from that pack within a one-minute window around the alert time.”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result: zero alerts. The agent ran one query for the 15-minute window, ran a second query to confirm the table had no rows, and then declined to invent any. It didn’t fabricate rows or an alert just because we’d asked for one. The MCP server’s error handling keeps errors distinct from success, and makes empty results easy to distinguish from silence.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Force the alert condition.&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;“Force a hot cell in &lt;code class="language-markup"&gt;bess&lt;/code&gt; so that the thermal-runaway trigger fires.”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent read the plugin source to learn the threshold (&lt;code class="language-markup"&gt;temperature_c &amp;gt; 70&lt;/code&gt;), then wrote one synthetic line-protocol row for &lt;code class="language-markup"&gt;pack-0/module-0/cell-0&lt;/code&gt; at 85 °C using &lt;code class="language-markup"&gt;write_line_protocol&lt;/code&gt;. The Processing Engine’s WAL trigger fired in-process on that write and emitted a row into &lt;code class="language-markup"&gt;alerts&lt;/code&gt;. No restart or orchestration is required because plugins run &lt;em&gt;inside&lt;/em&gt; InfluxDB 3.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Now run the original investigation.&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;“Show me the cell readings around that alert.”&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent’s first attempt asked for ±1 minute and received 1,542 rows, which it then narrowed to the hot cell’s timeline:&lt;/p&gt;

&lt;pre class=""&gt;&lt;code class="language-bash"&gt;time            voltage   temperature_c
14:12:41.617    3.643     22.08
14:12:57.071    3.646     22.20
14:13:07.557    3.650     85.00   ← injected, fires alert
14:13:12.529    3.646     22.00
14:13:27.989    3.646     21.90&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The temperature spike alone triggered the alert, but the agent also flagged what we should expect for a real thermal event: “in a real cell, an 85 °C excursion would correlate with voltage and current anomalies.”&lt;/p&gt;

&lt;p&gt;Five prompts, no handwritten SQL: discover the schema, read the current state, search alert events, write a single line of synthetic data to fire the trigger, and tie the resulting alert back to the underlying readings.&lt;/p&gt;

&lt;h2 id="links"&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/@influxdata/influxdb3-mcp-server"&gt;@influxdata/influxdb3-mcp-server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Docker Hub&lt;/strong&gt;: &lt;a href="https://hub.docker.com/r/influxdata/influxdb3-mcp-server"&gt;influxdata/influxdb3-mcp-server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/influxdata/influxdb3_mcp_server"&gt;github.com/influxdata/influxdb3_mcp_server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Release notes&lt;/strong&gt;: &lt;a href="https://github.com/influxdata/influxdb3_mcp_server/releases/tag/v1.3.0"&gt;v1.3.0 on GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Issues / tool requests&lt;/strong&gt;: &lt;a href="https://github.com/influxdata/influxdb3_mcp_server/issues"&gt;GitHub issues&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Earlier posts&lt;/strong&gt;: &lt;a href="https://www.influxdata.com/blog/influxdb-mcp-server/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;Introducing the MCP server&lt;/a&gt; · &lt;a href="https://www.influxdata.com/blog/influxdb-3-mcp-server-claude/?utm_source=website&amp;amp;utm_medium=influxdb_3_mcp_server_v1_3&amp;amp;utm_content=blog"&gt;Building with Claude&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it and tell us what’s missing.&lt;/p&gt;
</description>
      <pubDate>Thu, 28 May 2026 02:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/influxdb-3-mcp-server-v1-3/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/influxdb-3-mcp-server-v1-3/</guid>
      <category>Developer</category>
      <author>Jason Stirnaman (InfluxData)</author>
    </item>
  </channel>
</rss>
