Your DevExpress Website Is Slow. Here Is How to Fix It.
You built your application with DevExpress because it offered the richest set of UI controls on the market. Grids, charts, schedulers, dashboards, everything your users needed. It worked well at first. But as the data grew, the users multiplied, and the features piled on, the application started slowing down. Pages take 5, 10, sometimes 15 seconds to load. Users complain. The team patches things but nothing sticks.
This is the most common story I hear from businesses running DevExpress web applications. The good news is that a slow DevExpress website can almost always be fixed, usually without a rewrite. With over 10 years of DevExpress experience, I have optimized dozens of these applications and the patterns are remarkably consistent.
This guide covers the most impactful techniques I use to speed up DevExpress websites, with real code examples and before-and-after results.
Why DevExpress Websites Get Slow
DevExpress components are powerful, but that power comes with complexity. When developers use default settings or skip optimization, performance degrades fast. Here are the root causes I see in almost every slow DevExpress application:
Loading All Data at Once
The grid binds to a full dataset of 100K+ rows instead of using server-side paging. The server serializes everything, the network transfers it all, and the browser chokes rendering it.
Excessive Callbacks
Every sort, filter, page change, and group expansion triggers a full server callback. On a page with multiple DevExpress controls, a single user action can fire 3 to 5 server round trips.
Bloated ViewState
Web Forms applications store grid state, filter values, group structure, and sort order in ViewState. On complex pages this hidden field can reach 500KB or more, sent with every single postback.
Unoptimized SQL Queries
DevExpress grids generate SQL through LINQ or Entity Framework. Without proper indexing and query shaping, a simple grid page load can execute 20+ database queries taking seconds each.
No Caching Strategy
Lookup data, dropdown lists, and reference tables are fetched fresh on every request. Data that changes once a day is queried thousands of times.
Fix 1: Enable Server Mode for Large Datasets
This is the single most impactful change you can make to speed up a DevExpress website. Server Mode tells the grid to only fetch the rows it needs for the current page, and pushes sorting, filtering, and grouping to the database.
// Controller - loads entire table into memory
public ActionResult Orders()
{
var orders = db.Orders
.Include(o => o.Customer)
.Include(o => o.Products)
.ToList(); // 250,000 rows loaded into memory
return View(orders);
}
// View - grid binds to full collection
@Html.DevExpress().GridView(settings => {
settings.Name = "gvOrders";
settings.KeyFieldName = "OrderId";
settings.Columns.Add("OrderId");
settings.Columns.Add("CustomerName");
settings.Columns.Add("OrderDate");
settings.Columns.Add("Total");
}).Bind(Model).GetHtml()
// Controller - passes IQueryable, not materialized list
public ActionResult Orders()
{
var orders = db.Orders
.Include(o => o.Customer)
.Include(o => o.Products);
// No .ToList() - stays as IQueryable
return View(orders);
}
// View - grid uses server mode via GridViewModel
@Html.DevExpress().GridView(settings => {
settings.Name = "gvOrders";
settings.KeyFieldName = "OrderId";
settings.CallbackRouteValues =
new { Controller = "Orders", Action = "OrdersPartial" };
settings.SettingsPager.PageSize = 25;
// Enable server-side operations
settings.Settings.VerticalScrollBarMode =
ScrollBarMode.Visible;
settings.Settings.VerticalScrollableHeight = 500;
settings.SettingsBehavior.AllowFocusedRow = true;
settings.Columns.Add("OrderId");
settings.Columns.Add("CustomerName");
settings.Columns.Add("OrderDate");
settings.Columns.Add(col => {
col.FieldName = "Total";
col.PropertiesEdit.DisplayFormatString = "C2";
});
}).Bind(Model).GetHtml()
Result: Orders Grid - 250,000 Rows
Fix 2: Reduce Callback Overhead
DevExpress Web Forms controls use callbacks (partial postbacks) for nearly every interaction. Each callback sends the full ViewState to the server, processes on the backend, and returns updated HTML. When multiple controls sit on one page, callbacks stack up and the page feels sluggish.
// 1. Disable unnecessary auto-postbacks on filter controls
settings.Settings.ShowFilterRow = true;
settings.Settings.ShowFilterRowMenu = true;
settings.SettingsBehavior.FilterRowMode =
GridViewFilterRowMode.OnClick; // Not auto-filter on every keystroke
// 2. Use BeginCallback to show loading state and prevent double-clicks
settings.ClientSideEvents.BeginCallback =
"function(s,e) { LoadingPanel.Show(); }";
settings.ClientSideEvents.EndCallback =
"function(s,e) { LoadingPanel.Hide(); }";
// 3. Batch multiple operations into one callback
settings.SettingsBehavior.ProcessSelectionChangedOnServer = false;
settings.SettingsBehavior.AllowSelectByRowClick = true;
// 4. Use client-side grouping for small lookup columns
settings.Columns.Add(col => {
col.FieldName = "Status";
col.Settings.AllowGroup = DefaultBoolean.True;
col.Settings.GroupInterval = ColumnGroupInterval.Value;
});
Fix 3: Optimize SQL Behind the Grid
The fastest DevExpress grid in the world cannot fix a slow database query. When I profile slow DevExpress pages, SQL is the bottleneck more than half the time. Here are the patterns I fix repeatedly:
// Each row triggers a lazy-load query for Customer and Products
var orders = db.Orders.ToList();
// In the grid template:
// order.Customer.Name -- triggers SELECT * FROM Customers WHERE Id = @p0
// order.Products.Count() -- triggers SELECT COUNT(*) FROM Products WHERE OrderId = @p0
// Repeated for every single row = 247 queries
// Project exactly what the grid needs - single query
var orders = db.Orders
.Select(o => new OrderGridViewModel
{
OrderId = o.OrderId,
CustomerName = o.Customer.Name,
OrderDate = o.OrderDate,
Total = o.Total,
ProductCount = o.Products.Count(),
Status = o.Status.Name
})
.AsQueryable(); // Let DevExpress Server Mode handle paging/sorting
// Result: 1 SQL query with JOINs, server-side paging
// SQL Server does the heavy lifting, not your app server
Result: Query Optimization Impact
Fix 4: Implement Smart Caching
DevExpress pages often load the same reference data on every request: status dropdowns, category lists, user lookups, configuration values. Caching this data eliminates thousands of unnecessary database hits per hour.
public class LookupCache
{
private static readonly MemoryCache _cache =
MemoryCache.Default;
public static List<StatusItem> GetStatuses()
{
const string key = "lookup_statuses";
var result = _cache.Get(key) as List<StatusItem>;
if (result == null)
{
using (var db = new AppDbContext())
{
result = db.Statuses
.OrderBy(s => s.SortOrder)
.Select(s => new StatusItem
{
Id = s.Id,
Name = s.Name
})
.ToList();
}
_cache.Set(key, result, new CacheItemPolicy
{
AbsoluteExpiration =
DateTimeOffset.UtcNow.AddMinutes(30)
});
}
return result;
}
}
// In grid column setup - uses cached data instead of DB query
settings.Columns.Add(col => {
col.FieldName = "StatusId";
col.Caption = "Status";
col.EditorProperties().ComboBox(combo => {
combo.DataSource = LookupCache.GetStatuses();
combo.ValueField = "Id";
combo.TextField = "Name";
});
});
Fix 5: Tame ViewState and Page Size
DevExpress Web Forms controls can generate enormous ViewState. I have seen pages where the hidden __VIEWSTATE field alone was 800KB. That data is sent to the server and back on every single callback. Here is how to reduce it:
// 1. Enable callback mode instead of postback for grids
settings.SettingsBehavior.EnableCallBacks = true;
// 2. Disable ViewState for read-only display grids
settings.SettingsCookies.Enabled = true; // Use cookies instead
settings.SettingsCookies.StoreFiltering = true;
settings.SettingsCookies.StorePaging = true;
settings.SettingsCookies.StoreGroupingAndSorting = true;
// 3. Reduce columns sent to client - only include what is visible
settings.Columns.Add(col => {
col.FieldName = "InternalNotes";
col.Visible = false;
col.ShowInFilterControl = DefaultBoolean.False;
// Invisible columns with no filtering don't add to ViewState
});
// 4. Use binary serialization for ViewState (Web.config)
// <pages viewStateEncryptionMode="Never"
// enableViewStateMac="true" />
// 5. Store ViewState in session instead of hidden field
// <pages enableSessionState="true" />
// Override: PageStatePersister = new SessionPageStatePersister(this);
Fix 6: Optimize Grid Export
Exporting large DevExpress grids to Excel or PDF is one of the most common timeout scenarios. The default export tries to render every row, which fails on large datasets. Here is the correct approach:
public ActionResult ExportOrders()
{
// Use a lean query with only export-relevant columns
var data = db.Orders
.Select(o => new
{
o.OrderId,
CustomerName = o.Customer.Name,
o.OrderDate,
o.Total,
Status = o.Status.Name
})
.OrderByDescending(o => o.OrderDate);
var settings = new GridViewSettings();
settings.Name = "gvOrdersExport";
settings.Columns.Add("OrderId", "Order #");
settings.Columns.Add("CustomerName", "Customer");
settings.Columns.Add(col => {
col.FieldName = "OrderDate";
col.Caption = "Date";
col.PropertiesEdit.DisplayFormatString = "dd MMM yyyy";
});
settings.Columns.Add(col => {
col.FieldName = "Total";
col.PropertiesEdit.DisplayFormatString = "C2";
});
settings.Columns.Add("Status");
// Stream directly - don't load all into memory
return GridViewExtension.ExportToXlsx(
settings,
data,
new XlsxExportOptionsEx
{
ExportType = ExportType.DataAware,
SheetName = "Orders",
TextExportMode = TextExportMode.Value
}
);
}
Fix 7: Front-End Performance Wins
Server-side fixes get the biggest gains, but front-end optimization matters too. These changes reduce what the browser has to process and render:
- Bundle DevExpress scripts: Combine and minify the DevExpress JavaScript files instead of loading 15+ separate script files. Use the ASP.NET bundling system or the DevExpress script combiner
- Lazy-load hidden tabs and panels: If your page has tabbed sections with grids, only load the active tab's grid data. Use the Tab control's ActiveTabChanged event to fetch data on demand
- Reduce grid column count: Every visible column adds rendering cost. Hide columns that users rarely need behind a column chooser instead of rendering them all
- Optimize custom templates: Complex CellTemplate and DataItemTemplate delegates execute for every visible row. Keep template logic simple and avoid database calls inside templates
- Use virtual scrolling: For grids that need to display large result sets without pagination, enable virtual scrolling so only the visible rows are rendered in the DOM
settings.Settings.VerticalScrollBarMode = ScrollBarMode.Visible;
settings.Settings.VerticalScrollableHeight = 500;
settings.SettingsPager.Mode = GridViewPagerMode.ShowAllRecords;
// Combined with Server Mode, this gives you infinite-scroll
// behavior while only loading ~25 rows at a time from the DB
The Full Performance Checklist
Here is the checklist I work through on every DevExpress performance engagement. Use it to audit your own application:
Data Layer
Grid Configuration
Page and Network
Real-World Speed Improvements
Here are the results from three recent DevExpress optimization projects. Each followed the same methodology: profile first, fix the biggest bottlenecks, measure the results.
| Project | Problem | Before | After | Improvement |
|---|---|---|---|---|
| Insurance Claims Portal | Claims grid with 180K rows, 22 columns, no server mode | 12.3s | 0.8s | 93% faster |
| Warehouse Management | Inventory page with 5 grids, 340KB ViewState, N+1 queries | 9.7s | 1.2s | 88% faster |
| Financial Dashboard | Dashboard with charts, pivot grid, and 3 data grids loading on page open | 15.1s | 2.1s | 86% faster |
When to Call a DevExpress Specialist
If your DevExpress website is slow and your team has already tried the obvious fixes, it is time to bring in someone who has done this before. The patterns above are straightforward to describe, but applying them correctly in a production application with years of accumulated complexity requires experience and care.
I work with businesses worldwide to speed up their DevExpress websites without risky rewrites. Every engagement starts with a performance audit, follows with targeted fixes, and ends with measured, provable improvements. If your grids are slow, your callbacks are stacking up, or your exports are timing out, let's talk.
Technologies I Use
Frequently Asked Questions
How long does it take to speed up a DevExpress website?
+Most DevExpress performance engagements take between 1 and 3 weeks depending on the number of pages and the complexity of the data layer. The audit phase typically takes 2 to 3 days, and fixes are implemented incrementally with measurable results after each round.
Will speeding up the website require changing the UI?
+No. The majority of performance improvements happen in the data layer, grid configuration, and server-side code. Your users will see the same interface, it will just load much faster. In some cases I may recommend reducing page size from 100 rows to 25 rows, but even that is optional.
Can you optimize DevExpress Web Forms, MVC, and Blazor?
+Yes. I have optimized DevExpress applications across all platforms. Web Forms and MVC are the most common for performance work due to their longer histories and larger datasets, but I also work with Blazor Server and Blazor WebAssembly applications.
Do you provide before-and-after performance metrics?
+Always. Every engagement includes baseline measurements before any changes, and verified metrics after each optimization. You will see exact numbers for page load time, SQL query counts, memory usage, and network payload size.
What if our DevExpress version is outdated?
+I work with all DevExpress versions, including older releases. Many performance fixes apply regardless of version. If an upgrade would unlock significant improvements, I will recommend it and handle the migration as part of the engagement.