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:

01

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.

02

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.

03

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.

04

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.

05

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.

Before - Standard Binding (Slow) Loads all rows
// 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()
After - Server Mode (Fast) Only fetches visible rows
// 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

Initial Page Load
8.4s 0.6s
Sort Column Click
6.2s 0.3s
Server Memory
1.2 GB 85 MB
Network Payload
18 MB 42 KB

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.

Callback Optimization Techniques Reduce round trips
// 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:

Before - N+1 Query Problem 247 queries per page load
// 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
After - Eager Loading with Projection 1 query per page load
// 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

SQL Queries Per Page
247 1
Database Time
3,200ms 45ms
Grid Render Time
4.1s 0.4s

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.

Caching Lookup Data for DevExpress Dropdowns Cache reference data
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:

ViewState Reduction Techniques Shrink page payload
// 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:

Efficient Grid Export for Large Datasets Stream-based export
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
Enable Virtual Scrolling Only renders visible rows
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

Server Mode enabled for grids with 10K+ rows
No N+1 query patterns in grid data sources
Projections used instead of full entity loading
Database indexes cover grid sort and filter columns
Lookup/reference data is cached

Grid Configuration

Page size is 25 or fewer (not 100+)
Filter row uses OnClick mode, not auto-filter
Unused columns removed or hidden
Cell templates are lightweight (no DB calls)
Export uses DataAware mode with lean queries

Page and Network

ViewState is under 100KB
DevExpress scripts are bundled and minified
Hidden tabs load data on demand
Loading panels shown during callbacks
HTTP compression enabled (gzip/brotli)

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

.NET Core ASP.NET MVC C# SQL Server Azure Entity Framework

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.