LVGL vs. Custom Drawing: Why GUI Builders Win for Production
Published on Lopaka.app — The free web-based LVGL GUI builder for embedded developers
Introduction
If you're building a GUI for an embedded display, you're facing a fundamental decision: use a framework like LVGL, or roll your own drawing code?
The debate comes up constantly in embedded communities. On one side, purists argue that custom drawing gives you maximum control and minimum overhead. On the other, pragmatists point out that reinventing the wheel is a terrible use of engineering time.
I've spent the last year building Lopaka — a visual GUI builder for LVGL — and watching dozens of teams ship products with it. The data is clear, but the answer is more nuanced than you might expect.
In this post, I'll break down the real tradeoffs between LVGL and custom drawing, share performance benchmarks, and tell you exactly when to use each approach.
What Is LVGL?
LVGL (Light and Versatile Graphics Library) is the most popular open-source graphics library for embedded systems. It provides:
- Widgets: Buttons, labels, sliders, charts, gauges, keyboards, and 35+ more
- Layout engines: Flexbox and grid layouts (yes, like CSS)
- Styling system: CSS-like styling with states, transitions, and inheritance
- Input handling: Touch, encoder, keyboard, button support
- Animations: Built-in animation engine with easing functions
- Memory management: Optimized for MCUs with as little as 32KB RAM
It runs on everything from ESP32 to STM32 to Raspberry Pi, and it's MIT licensed.
What Is Custom Drawing?
Custom drawing means you write your own code to render pixels to the display:
// Custom drawing approach
tft.fillScreen(TFT_BLACK);
tft.drawString("Temperature", 10, 10);
tft.drawNumber(25, 10, 30);
tft.drawRect(10, 60, 300, 40, TFT_WHITE);
// ... repeat for every element, every frameYou handle everything: positioning, redrawing, input detection, state management, animations.
Head-to-Head Comparison
Development Time
| Metric | LVGL | Custom Drawing |
|---|---|---|
| Simple screen (3-5 elements) | 15-30 min | 1-2 hours |
| Complex screen (10+ elements) | 1-2 hours | 4-8 hours |
| Multi-screen app (5 screens) | 4-6 hours | 20-40 hours |
| Adding animations | 10 min | 2-4 hours |
| Adding touch input | 5 min | 1-2 hours |
Winner: LVGL by a massive margin.
With a visual builder like Lopaka, these times drop even further — most simple screens take under 10 minutes to design and export.
Code Maintainability
LVGL approach:
// Clear, semantic code
lv_obj_t *temp_label = lv_label_create(lv_scr_act());
lv_label_set_text(temp_label, "25°C");
lv_obj_align(temp_label, LV_ALIGN_CENTER, 0, -20);
// Easy to modify
void update_temp(float value) {
lv_label_set_text_fmt(temp_label, "%.1f°C", value);
}Custom drawing approach:
// Manual pixel management
void draw_temp(int x, int y, float value) {
char buf[16];
sprintf(buf, "%.1f°C", value);
// Must clear old text first
tft.fillRect(x-5, y-5, 80, 20, TFT_BLACK);
tft.drawString(buf, x, y);
}Winner: LVGL. Semantic widget code is self-documenting. Custom drawing code requires comments to explain what each rectangle does.
Performance
Here's where it gets interesting. Let's benchmark on an ESP32 with ILI9341 display:
| Metric | LVGL | Custom Drawing |
|---|---|---|
| RAM usage (simple UI) | 15-25 KB | 2-5 KB |
| RAM usage (complex UI) | 40-80 KB | 10-20 KB |
| Flash size | 80-120 KB | 10-30 KB |
| Frame rate (simple UI) | 30-60 fps | 50-60 fps |
| Frame rate (complex UI) | 20-40 fps | 30-50 fps |
| CPU usage (idle) | 2-5% | 0-1% |
| CPU usage (active) | 15-30% | 5-15% |
Winner: Custom drawing for raw performance, but the gap is smaller than you'd think.
For most applications, LVGL's performance is more than adequate. The 20-40 fps you get on complex UIs is visually smooth, and the CPU usage leaves plenty of headroom for your application logic.
Where custom drawing wins:
- Ultra-low-power devices (battery-powered sensors that sleep 99% of the time)
- Extremely resource-constrained MCUs (< 64KB RAM)
- High-speed data visualization (oscilloscopes, real-time graphs at 100+ fps)
Where LVGL wins:
- Anything with user interaction (buttons, menus, forms)
- Multi-screen applications
- Products that need to look professional
- Teams with more than one developer
Development Experience
This is subjective but important. Ask yourself:
- Do you want to spend your time on your product's unique features, or on drawing rectangles?
- How will you handle touch input? Hit detection? Button debouncing?
- What about keyboard navigation for accessibility?
- How do you implement smooth transitions between screens?
- Who maintains this code when you leave?
Winner: LVGL. It solves problems you haven't even thought of yet.
The Real Cost Analysis
Let's put this in business terms. Assume an embedded developer costs $80/hour:
| Approach | Development Time | Cost | Ongoing Maintenance |
|---|---|---|---|
| Custom drawing (simple) | 40 hours | $3,200 | $400/month |
| Custom drawing (complex) | 160 hours | $12,800 | $800/month |
| LVGL (hand-coded) | 20 hours | $1,600 | $200/month |
| LVGL + Lopaka | 8 hours | $640 | $100/month |
The tooling choice that saves the most money isn't the one with the smallest binary — it's the one that lets your team ship faster.
When to Use Each Approach
Use Custom Drawing When:
- You have extreme resource constraints — < 32KB RAM, < 128KB flash
- Your UI is static — A single screen that never changes (e.g., a temperature readout)
- You need maximum frame rate — Oscilloscopes, logic analyzers, real-time graphs
- You're building a library, not a product — You need zero dependencies
- You enjoy it — Some developers genuinely like writing rendering code
Use LVGL When:
- Your UI has user interaction — Buttons, menus, forms, settings screens
- You have multiple screens — Navigation, tabs, modals
- You need it to look professional — Product demos, customer-facing devices
- You're on a timeline — Ship in weeks, not months
- You're a team — Multiple developers need to work on the UI
- You want it to be maintainable — Someone else will touch this code
The Hybrid Approach
The smartest teams I work with use a hybrid approach:
- LVGL for the main UI — Menus, settings, configuration screens
- Custom drawing for specialized views — Real-time graphs, custom visualizations
- Lopaka for rapid prototyping — Design the LVGL portions visually, iterate quickly
// Main screens use LVGL (designed in Lopaka)
lv_obj_t *main_screen = ui_MainScreen_create();
// Specialized view uses custom drawing
lv_obj_t *graph_canvas = lv_canvas_create(lv_scr_act());
lv_canvas_fill_bg(graph_canvas, lv_color_black(), LV_OPA_COVER);
// Custom rendering code for high-speed data visualization
draw_oscilloscope_trace(graph_canvas, samples, num_samples);This gives you the best of both worlds: rapid development for 90% of your UI, and maximum control for the 10% that needs it.
Common Objections (And Why They're Wrong)
"LVGL is too heavy"
LVGL's minimum configuration runs in 32KB RAM and 80KB flash. That's less than most Arduino sketches. The "heavy" reputation comes from default configurations that enable every feature.
"I need pixel-perfect control"
LVGL gives you pixel-perfect control — you can position anything exactly where you want. The difference is you're not forced to calculate every coordinate manually.
"Custom code is more efficient"
For raw rendering, yes. For the complete user experience (input handling, state management, animations, accessibility), LVGL is dramatically more efficient because it's already written and tested.
"I don't want external dependencies"
LVGL is MIT licensed, has zero dependencies, and is used in production by thousands of companies. It's as close to "no dependency" as you can get for a graphics library.
The Bottom Line
| Criteria | Winner |
|---|---|
| Development speed | LVGL |
| Code maintainability | LVGL |
| Raw performance | Custom drawing |
| Resource usage | Custom drawing |
| Professional appearance | LVGL |
| Team collaboration | LVGL |
| Long-term maintenance | LVGL |
| Learning curve | Custom drawing (initially) |
For 90% of embedded GUI projects, LVGL is the right choice. The performance tradeoff is negligible for most applications, and the development time savings are enormous.
The remaining 10% — ultra-constrained devices, high-speed visualizations, static displays — are better served by custom drawing.
And for the LVGL projects? Using a visual builder like Lopaka makes the decision even easier. You get LVGL's power with a fraction of the development time.
Resources
- Lopaka.app — Visual LVGL GUI builder
- LVGL Documentation — Official LVGL docs
- LVGL GitHub — Source code and examples
- Lopaka Discord — Community and support
Still on the fence? Try building the same screen both ways and time yourself. I think you'll be surprised.