<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yongho Hwang</title>
    <description>The latest articles on DEV Community by Yongho Hwang (@jogakdal).</description>
    <link>https://dev.to/jogakdal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4165063%2Fbdb66bb6-8e1a-4ee0-b6cb-6133e2216bec.png</url>
      <title>DEV Community: Yongho Hwang</title>
      <link>https://dev.to/jogakdal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jogakdal"/>
    <language>en</language>
    <item>
      <title>[query-inspector] A Claude Code skill for extracting and tuning SQL/ORM queries</title>
      <dc:creator>Yongho Hwang</dc:creator>
      <pubDate>Tue, 06 Oct 2026 07:13:37 +0000</pubDate>
      <link>https://dev.to/jogakdal/query-inspector-a-claude-code-skill-for-extracting-and-tuning-sqlorm-queries-4kaf</link>
      <guid>https://dev.to/jogakdal/query-inspector-a-claude-code-skill-for-extracting-and-tuning-sqlorm-queries-4kaf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;query-inspector&lt;/strong&gt; is a Claude Code skill that extracts the SQL/ORM queries from your project's source, then diagnoses and tunes &lt;strong&gt;missing indexes / N+1 problems / anti-patterns&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Queries that run fine until the data piles up. N+1 problems that sail through code review. The real SQL your ORM generates, invisible in the code. It catches all of this right before you commit, not after it reaches production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Common pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A query shipped without an index suddenly turns into a full scan once there are tens of thousands of rows.&lt;/li&gt;
&lt;li&gt;An N+1 problem slips through code review, and a single list API fires dozens of queries.&lt;/li&gt;
&lt;li&gt;You can't tell from the code alone what SQL JPA or QueryDSL will actually generate.&lt;/li&gt;
&lt;li&gt;Code review looks at logic, not "the queries this change will produce" from a SQL angle.&lt;/li&gt;
&lt;li&gt;QA rarely catches it either, because its test data is too small for a missing index or an N+1 to surface as a slowdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems share one trait: &lt;strong&gt;they surface only after you ship.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;query-inspector moves that moment to just before the commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;It's a Claude Code plugin, made of two skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;tuning-report&lt;/code&gt;&lt;/strong&gt; - extracts the SQL/ORM queries in your git changes, diagnoses &lt;strong&gt;missing indexes / N+1s / anti-patterns&lt;/strong&gt;, and produces a report with fixes you can apply right away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;inventory-report&lt;/code&gt;&lt;/strong&gt; - catalogs the queries your project runs, down to the &lt;strong&gt;full query body and index coverage&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither one touches your code; they only produce reports.&lt;/p&gt;

&lt;p&gt;Run it right before a commit, and it surfaces performance problems that would otherwise appear only after you ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;p&gt;There were already ways to check query performance: runtime SQL logging (p6spy, Hibernate statistics) or APM. But those surface a problem only &lt;strong&gt;after&lt;/strong&gt; the query runs.&lt;/p&gt;

&lt;p&gt;query-inspector checks &lt;strong&gt;before anything runs, on the changes you're about to commit&lt;/strong&gt;. Inferring the SQL an ORM will generate without executing it is an approach that only became practical with recent advances in AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Only your changes, in your commit flow
&lt;/h3&gt;

&lt;p&gt;It analyzes only &lt;strong&gt;what changed since your last tuning&lt;/strong&gt;, not the whole project every time. That keeps it fast and lets it sit naturally in your usual &lt;code&gt;git add&lt;/code&gt; -&amp;gt; run query-inspector -&amp;gt; commit flow.&lt;/p&gt;

&lt;p&gt;A full-project scan is available too.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL the code doesn't directly reveal
&lt;/h3&gt;

&lt;p&gt;Explicit SQL is taken as-is, and for &lt;strong&gt;JPA derived methods / &lt;code&gt;@Query&lt;/code&gt; / QueryDSL / Kotlin JDSL / MyBatis dynamic queries&lt;/strong&gt; it infers the SQL that will actually be generated, then analyzes or catalogs it.&lt;/p&gt;

&lt;p&gt;Every query carries an &lt;code&gt;EXACT&lt;/code&gt; / &lt;code&gt;INFERRED&lt;/code&gt; / &lt;code&gt;AMBIGUOUS&lt;/code&gt; confidence label, so you know how far to trust each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  From static analysis to a live EXPLAIN - as deep as you want
&lt;/h3&gt;

&lt;p&gt;Even without a database it catches most problems (missing indexes / N+1s / SQL-dialect mismatches / anti-patterns).&lt;/p&gt;

&lt;p&gt;It connects to your development database and runs a real &lt;strong&gt;&lt;code&gt;EXPLAIN&lt;/code&gt;&lt;/strong&gt; only when you want more certainty.&lt;/p&gt;

&lt;p&gt;For safety, production hosts are blocked by default, and only read-only queries run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reports you can act on immediately
&lt;/h3&gt;

&lt;p&gt;It doesn't stop at "this might be slow."&lt;/p&gt;

&lt;p&gt;You get a &lt;strong&gt;&lt;code&gt;CREATE INDEX&lt;/code&gt; statement&lt;/strong&gt; with the right column order, the exact &lt;code&gt;file:line&lt;/code&gt;, and copy-ready &lt;strong&gt;Action Items&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A developer, or the AI assisting that developer, can read the report and start fixing right away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow-up on past suggestions
&lt;/h3&gt;

&lt;p&gt;It compares the previous run's suggestions against your current code and flags the ones &lt;strong&gt;still not applied&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even files you didn't touch this run are included in the check.&lt;/p&gt;

&lt;h3&gt;
  
  
  JVM-first stacks, localized reports
&lt;/h3&gt;

&lt;p&gt;The current version focuses on Kotlin/Java (JPA, Hibernate, QueryDSL, MyBatis, native SQL). Python (Django/SQLAlchemy) is supported too, though not as thoroughly validated as the primary stacks.&lt;/p&gt;

&lt;p&gt;More stacks are planned.&lt;/p&gt;

&lt;p&gt;SQL dialects (MySQL/MariaDB, PostgreSQL) are auto-detected.&lt;/p&gt;

&lt;p&gt;Reports come out in the language you're chatting with Claude in (you can also force a specific one).&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample reports
&lt;/h2&gt;

&lt;p&gt;A slice of what &lt;code&gt;tuning-report&lt;/code&gt; produces after scanning your changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Query Tuning Report - incremental (2 changed files)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Severity (open): 🔴 3 / 🟡 2 / ⚪ 1   /   Follow-up: ✅ 2 resolved / ⚠️ 2 still open

&lt;span class="gu"&gt;## 🔴 [critical] Missing index - FK `orders.user_id` - OrderMapper.xml&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Why critical: it is the N+1 child query, so every user triggers a full scan of &lt;span class="sb"&gt;`orders`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Suggestion:  CREATE INDEX idx_orders_user_id ON orders (user_id);
&lt;span class="p"&gt;-&lt;/span&gt; Verify (live EXPLAIN): &lt;span class="sb"&gt;`type: ALL -&amp;gt; ref`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point the same project at &lt;code&gt;inventory-report&lt;/code&gt; and it lists the queries as a &lt;strong&gt;catalog&lt;/strong&gt; instead of tuning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Query Inventory&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Queries: 24 ( SELECT 18 / INSERT 3 / UPDATE 2 / DELETE 1 )

&lt;span class="gu"&gt;#### [order-03] Orders for a given user&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Source: OrderMapper.xml:42 (selectOrdersByUser) / Type: SELECT
&lt;span class="p"&gt;-&lt;/span&gt; Target: orders / Access columns: WHERE user_id, ORDER BY created_at
&lt;span class="p"&gt;-&lt;/span&gt; Index coverage: ❌ uncovered (no index on user_id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the tuning report to find what to fix, and the inventory to see everything that runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Install and usage are in the GitHub README: &lt;strong&gt;&lt;a href="https://github.com/jogakdal/query-inspector" rel="noopener noreferrer"&gt;github.com/jogakdal/query-inspector&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have Claude Code, you can install it with these two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add jogakdal/query-inspector
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;query-inspector@query-inspector-marketplace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to see the output first? Browse the &lt;a href="https://github.com/jogakdal/query-inspector/blob/main/examples/sample-report.md" rel="noopener noreferrer"&gt;sample report&lt;/a&gt; and the &lt;a href="https://github.com/jogakdal/query-inspector/tree/main/examples/docker-mysql" rel="noopener noreferrer"&gt;Docker example&lt;/a&gt; in the repo.&lt;/p&gt;

&lt;p&gt;It's still v1.0.0. After trying it, please file feedback via &lt;a href="https://github.com/jogakdal/query-inspector/issues" rel="noopener noreferrer"&gt;GitHub issues&lt;/a&gt; and it'll go into the next iteration; a star is welcome if you find it useful.&lt;/p&gt;

&lt;p&gt;Run it before your next commit.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>sql</category>
      <category>java</category>
      <category>performance</category>
    </item>
    <item>
      <title>Stop writing Excel reports cell by cell - bind data to templates instead (Kotlin/Java)</title>
      <dc:creator>Yongho Hwang</dc:creator>
      <pubDate>Tue, 06 Oct 2026 06:43:47 +0000</pubDate>
      <link>https://dev.to/jogakdal/stop-writing-excel-reports-cell-by-cell-bind-data-to-templates-instead-kotlinjava-1n3l</link>
      <guid>https://dev.to/jogakdal/stop-writing-excel-reports-cell-by-cell-bind-data-to-templates-instead-kotlinjava-1n3l</guid>
      <description>&lt;h2&gt;
  
  
  Still crafting Excel reports cell by cell with POI?
&lt;/h2&gt;

&lt;p&gt;If you've ever built Excel reports in a JVM environment, you know the pain of Apache POI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Using Apache POI directly...&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;workbook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;XSSFWorkbook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sheet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workbook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Employee Status"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;headerRow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;headerRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;headerRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Position"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;headerRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Salary"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEachIndexed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emp&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;row&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setCellValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDouble&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Column widths, styles, formulas, charts... it never ends&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One header, one cell, one style at a time... hundreds of lines for a single report.&lt;/p&gt;

&lt;p&gt;Add &lt;strong&gt;charts&lt;/strong&gt;, &lt;strong&gt;conditional formatting&lt;/strong&gt;, &lt;strong&gt;formulas&lt;/strong&gt;, and &lt;strong&gt;images&lt;/strong&gt; on top? The code spirals out of control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TBEG (Template Based Excel Generator)&lt;/strong&gt; solves this at its root - &lt;em&gt;design the report in Excel, then just bind your data.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is TBEG?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A JVM library that generates reports by binding data to Excel templates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core idea is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A designer (or you) &lt;strong&gt;designs the report layout directly in Excel&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Place &lt;code&gt;${variableName}&lt;/code&gt; markers where data should go&lt;/li&gt;
&lt;li&gt;In your code, &lt;strong&gt;just pass the data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;TBEG combines template + data to produce the final report
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Using TBEG - this is all you need to do&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"Employee Status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"employees"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;employeeList&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;ExcelGenerator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.xlsx"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Formatting, charts, formulas, and conditional formatting are &lt;strong&gt;all managed in the template&lt;/strong&gt;. Your code focuses solely on data binding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design Philosophy
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We don't reinvent what Excel already provides - we use it as-is.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Aggregation with Excel's &lt;code&gt;=SUM()&lt;/code&gt; formula, averages with &lt;code&gt;=AVERAGE()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Conditional highlighting with conditional formatting&lt;/li&gt;
&lt;li&gt;Visualization with charts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the familiar Excel features as they are.&lt;/p&gt;

&lt;p&gt;TBEG adds &lt;strong&gt;dynamic data binding&lt;/strong&gt; on top, and automatically adjusts these features to work as intended even when data expands.&lt;/p&gt;




&lt;h2&gt;
  
  
  At a Glance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Template
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhxlu5ve6qk221u52vvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhxlu5ve6qk221u52vvu.png" alt="Template" width="800" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;simpleDataProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reportTitle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Q1 2026 Sales Performance Report"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"period"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Jan 2026 ~ Mar 2026"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Yongho Hwang"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reportDate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logoBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;imageUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ci"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://example.com/ci.png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// URL supported&lt;/span&gt;
    &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"depts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;deptList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;productList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"employees"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;employeeList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;ExcelGenerator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"quarterly_report"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftrrieomvzcn7p6rxitzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftrrieomvzcn7p6rxitzy.png" alt="Result" width="800" height="842"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Variable substitution, image insertion, repeat data expansion, automatic cell merge, formula range adjustment, conditional formatting duplication, and chart data reflection - &lt;strong&gt;TBEG handles all of this automatically&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Template-based generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Generate reports by binding data to Excel templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Repeat data processing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Expand list data into rows/columns with ${repeat(...)} syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Variable substitution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bind values to cells, charts, shapes, headers/footers, formula arguments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image insertion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Insert dynamic images via byte arrays or URLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automatic cell merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-merge consecutive cells with the same value in repeat data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bundle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Group multiple elements into a single unit that moves together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Selective field visibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Restrict visibility of specific fields based on conditions. Choose between DELETE or DIM modes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Formula auto-adjustment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically update formula ranges (SUM, AVERAGE, etc.) on data expansion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automatic conditional formatting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically apply original conditional formatting to repeated rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automatic data validation expansion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically apply original data validation (dropdowns, etc.) to repeated rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chart/pivot table auto-reflection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically reflect expanded data ranges in charts. Pivot table source range auto-adjustment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File encryption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Set open password for generated Excel files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Document metadata&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Set document properties such as title, author, keywords, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Large-scale processing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reliably process over 1 million rows with low CPU utilization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Asynchronous processing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Process large data in the background&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lazy loading&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Memory-efficient data processing via DataProvider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spring Boot support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easy integration with auto-configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Template Syntax Preview
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;${variableName}&lt;/td&gt;
&lt;td&gt;Variable substitution&lt;/td&gt;
&lt;td&gt;${title}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${object.field}&lt;/td&gt;
&lt;td&gt;Repeat item field&lt;/td&gt;
&lt;td&gt;${emp.name}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${repeat(collection, range, object)}&lt;/td&gt;
&lt;td&gt;Repeat processing&lt;/td&gt;
&lt;td&gt;${repeat(items, A2:C2, item)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${image(name)}&lt;/td&gt;
&lt;td&gt;Image insertion&lt;/td&gt;
&lt;td&gt;${image(logo)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${merge(object.field)}&lt;/td&gt;
&lt;td&gt;Automatic cell merge&lt;/td&gt;
&lt;td&gt;${merge(emp.dept)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${bundle(range)}&lt;/td&gt;
&lt;td&gt;Bundle&lt;/td&gt;
&lt;td&gt;${bundle(A5:H12)}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;${hideable(object.field, range, mode)}&lt;/td&gt;
&lt;td&gt;Selective field visibility&lt;/td&gt;
&lt;td&gt;${hideable(emp.salary, C1:C3, DIM)}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;TBEG internally generates data using streaming, producing 1 million rows in about 3.2 seconds while using around 9% of system CPU. Both rendering and post-processing operate in streaming mode, using a constant memory buffer regardless of data size.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Size&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;CPU Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1,000 rows&lt;/td&gt;
&lt;td&gt;13ms&lt;/td&gt;
&lt;td&gt;25.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10,000 rows&lt;/td&gt;
&lt;td&gt;47ms&lt;/td&gt;
&lt;td&gt;17.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30,000 rows&lt;/td&gt;
&lt;td&gt;117ms&lt;/td&gt;
&lt;td&gt;13.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100,000 rows&lt;/td&gt;
&lt;td&gt;354ms&lt;/td&gt;
&lt;td&gt;11.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000,000 rows&lt;/td&gt;
&lt;td&gt;3,203ms&lt;/td&gt;
&lt;td&gt;9.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Comparison with Other Libraries (100,000 rows)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TBEG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.35s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JXLS (STREAMING_ON)&lt;/td&gt;
&lt;td&gt;0.73s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(ref.) JXLS (STREAMING_OFF)&lt;/td&gt;
&lt;td&gt;2.63s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The direct comparison target is &lt;strong&gt;JXLS STREAMING_ON&lt;/strong&gt;, which shares the same output conditions. STREAMING_OFF (full in-memory mode) is a reference figure.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Most Common Use Case: Excel Download API
&lt;/h2&gt;

&lt;p&gt;In practice, TBEG is most frequently used for &lt;strong&gt;Excel download features in web applications&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/reports/download"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;downloadReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reportService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReportData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;template&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resourceLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"classpath:templates/report.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contentType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Disposition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"attachment; filename=report.xlsx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;excelGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Admin page list exports, settlement report downloads, monthly report generation - set up one template and this is all the code you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use TBEG
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Generating standardized reports/statements&lt;/li&gt;
&lt;li&gt;✅ Filling data into Excel forms provided by a designer&lt;/li&gt;
&lt;li&gt;✅ Reports requiring complex formatting (conditional formatting, charts)&lt;/li&gt;
&lt;li&gt;✅ Processing large datasets with tens to hundreds of thousands of rows&lt;/li&gt;
&lt;li&gt;✅ Tables where the number of rows or columns changes with the data&lt;/li&gt;
&lt;li&gt;✅ Implementing Excel download APIs in Spring Boot environments&lt;/li&gt;
&lt;li&gt;❌ Reading/parsing Excel files (TBEG is generation-only)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// build.gradle.kts&lt;/span&gt;
&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.github.jogakdal:tbeg:1.2.5"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gradle (Groovy DSL)&lt;/span&gt;
&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.github.jogakdal:tbeg:1.2.5'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Maven --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.github.jogakdal&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;tbeg&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.2.5&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The version above is as of this writing. Check the latest version on &lt;a href="https://central.sonatype.com/artifact/io.github.jogakdal/tbeg" rel="noopener noreferrer"&gt;Maven Central&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Quick Start (Kotlin)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.github.jogakdal.tbeg.ExcelGenerator&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.File&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"title"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"Employee Status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"employees"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Yongho Hwang"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Director"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Yongho Han"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Manager"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nc"&gt;ExcelGenerator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;template&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"template.xlsx"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;inputStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.xlsx"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick Start (Java)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.github.jogakdal.tbeg.ExcelGenerator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.nio.file.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Example&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Employee Status"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"employees"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Yongho Hwang"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"position"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Director"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"salary"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Yongho Han"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"position"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Manager"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"salary"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6500&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExcelGenerator&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"template.xlsx"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.xlsx"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;p&gt;This is the first post in the &lt;strong&gt;TBEG series&lt;/strong&gt;. In the next post, we'll walk through creating a template and binding data step by step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/jogakdal/data-processors-with-excel" rel="noopener noreferrer"&gt;jogakdal/data-processors-with-excel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maven Central&lt;/strong&gt;: &lt;a href="https://central.sonatype.com/artifact/io.github.jogakdal/tbeg" rel="noopener noreferrer"&gt;tbeg&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📖 &lt;strong&gt;Documentation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/user-guide.md" rel="noopener noreferrer"&gt;User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/reference/template-syntax.md" rel="noopener noreferrer"&gt;Template Syntax Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/reference/api-reference.md" rel="noopener noreferrer"&gt;API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/examples/basic-examples.md" rel="noopener noreferrer"&gt;Basic Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/examples/advanced-examples.md" rel="noopener noreferrer"&gt;Advanced Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jogakdal/data-processors-with-excel/blob/main/modules/tbeg/manual/en/examples/spring-boot-examples.md" rel="noopener noreferrer"&gt;Spring Boot Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;⭐ &lt;strong&gt;Found TBEG useful?&lt;/strong&gt; &lt;a href="https://github.com/jogakdal/data-processors-with-excel" rel="noopener noreferrer"&gt;Star it on GitHub&lt;/a&gt; - it really helps the project grow.&lt;/p&gt;

</description>
      <category>java</category>
      <category>kotlin</category>
      <category>excel</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
