Converting MATLAB Web Apps to HTML Apps Backed by MATLAB Production Server

A step-by-step guide for converting MATLAB Web Apps to HTML/CSS/JavaScript front ends backed by MATLAB Production Server APIs.

1. Overview and Approach

A MATLAB Web App (.mlapp) bundles both the UI rendering logic and the computational logic into a single artifact that runs inside the MATLAB Desktop or MATLAB Web App Server. Converting to an HTML app requires us to decouple these two concerns:

This separation brings several advantages: the front end is lighter and more customizable, the MATLAB computation scales independently, and the two layers can be developed and maintained by different teams.

The general workflow is:

  1. Screenshot and document every interaction in the original .mlapp.
  2. Extract the algorithmic callback logic into a standalone MATLAB function.
  3. Build an HTML/JS front end that replicates the original UI.
  4. Replace MATLAB plots with Chart.js or Plotly.js equivalents.
  5. Compile the MATLAB function, deploy to MATLAB Production Server, and wire the front end to the API.

2. Documenting the Original App with Screenshots

Before writing any code, create a comprehensive visual record of the original MATLAB Web App. This serves as your specification and ensures nothing is lost in translation.

What to Capture

Take one screenshot per distinct user interaction. At minimum, capture:

Naming Convention

Use a consistent naming scheme for your screenshot files:

01_initial_state.png
02_input_filled.png
03_dropdown_selected.png
04_calculate_clicked.png
05_plot_result.png
06_error_validation.png

How to Use the Screenshots

When working with an AI assistant (such as Claude) to help build the new front end, attach the screenshot as context. The assistant can analyze the layout, identify UI components (text fields, dropdowns, buttons, axes), and suggest the corresponding HTML/CSS structure. One screenshot per prompt interaction keeps things focused and prevents the AI from missing details.

3. Example Prompts for AI-Assisted Conversion

Using an AI assistant to accelerate the conversion is highly effective. Below are example prompts you can adapt for each stage of the process. Each prompt assumes you are attaching the relevant screenshot(s).

Prompt 1: Analyze the Original App Layout

[Attach: 01_initial_state.png]

Prompt

This is a screenshot of a MATLAB Web App (.mlapp). I want to recreate this UI as a standalone HTML/CSS/JavaScript page. Please identify all the UI components visible (text fields, labels, dropdowns, buttons, plot axes, tables) and suggest an HTML structure using Bootstrap 5 for layout. Keep the same general arrangement.

Prompt 2: Build the HTML Skeleton

Prompt

Based on the UI components you identified, create a complete single-page HTML file with Bootstrap 5. Include placeholder <div> elements for each chart area. Use <input>, <select>, and <button> elements matching the original app controls. Add id attributes to every interactive element so I can wire them up to JavaScript later.

Prompt 3: Extract the MATLAB Callback Logic

[Attach: 04_calculate_clicked.png and/or the .mlapp source]

Prompt

Here is the callback code from my MATLAB Web App's "Calculate" button. It reads values from UI components like app.FrequencyEditField.Value and app.AmplitudeDropDown.Value, performs a computation, and plots the result to app.UIAxes. Please refactor this into a standalone MATLAB function with explicit input arguments and output arguments. Remove all app.* references.

Prompt 4: Create the JavaScript Chart

[Attach: 05_plot_result.png]

Prompt

This is what the MATLAB plot looks like. Please create the equivalent chart using Chart.js (or Plotly.js). The x-axis represents frequency in Hz and the y-axis represents amplitude in dB. Use the same axis labels and a similar color scheme. The data will come from a JSON API response -- just use placeholder arrays for now.

Prompt 5: Wire Up the API Call

Prompt

Now connect the front end to MATLAB Production Server. When the user clicks "Calculate", gather the input values from the HTML form, construct a JSON payload matching the MATLAB Production Server schema, POST it to the Production Server endpoint, parse the response from lhs.mwdata, and pass the result arrays to the Chart.js chart to update the display.

Prompt 6: Iterate on Styling and Behavior

[Attach: side-by-side of original vs. current HTML]

Prompt

Here is the original MATLAB app and my current HTML version. Can you adjust the styling to more closely match the original? Specifically, the button should be blue, the chart area should have a light gray background, and the input fields should be arranged in two columns.

4. Separating UI Logic from Algorithm Logic

This is the most difficult step in the migration. In a MATLAB Web App, callback functions typically interleave UI reads, computation, and UI writes. You need to tease these apart.

Anatomy of a Typical .mlapp Callback

% Inside the .mlapp (before refactoring)
function CalculateButtonPushed(app, event)
    % UI READ -- get values from widgets
    freq = app.FrequencyEditField.Value;
    amp = app.AmplitudeDropDown.Value;
    duration = app.DurationSlider.Value;
    method = app.MethodDropDown.Value;

    % ALGORITHM -- the core computation
    t = 0:1/1000:duration;
    switch method
        case 'Sine'
            signal = amp * sin(2 * pi * freq * t);
        case 'Square'
            signal = amp * square(2 * pi * freq * t);
    end
    spectrum = abs(fft(signal));
    freqAxis = linspace(0, 1000, length(spectrum));

    % UI WRITE -- display results
    plot(app.UIAxes, t, signal);
    title(app.UIAxes, 'Generated Signal');
    app.RMSLabel.Text = sprintf('RMS: %.4f', rms(signal));
end

Step 1: Identify the Three Zones

Go through each callback and mark every line as belonging to one of three categories:

Step 2: Extract the Algorithm into a Standalone Function

Create a new .m file with a function signature that takes the UI-read values as inputs and returns the UI-write data as outputs.

function [t, signal, freqAxis, spectrum, rmsValue] = generateSignal(freq, amp, duration, method)
    % generateSignal - Core algorithm extracted from MATLAB Web App
    %
    % Inputs:
    %   freq     - Frequency in Hz (double)
    %   amp      - Amplitude (double)
    %   duration - Duration in seconds (double)
    %   method   - Waveform type: 'Sine' or 'Square' (string)
    %
    % Outputs:
    %   t        - Time vector (1xN double)
    %   signal   - Generated signal (1xN double)
    %   freqAxis - Frequency axis for spectrum (1xM double)
    %   spectrum - FFT magnitude spectrum (1xM double)
    %   rmsValue - RMS value of signal (scalar double)

    t = 0:1/1000:duration;

    switch method
        case 'Sine'
            signal = amp * sin(2 * pi * freq * t);
        case 'Square'
            signal = amp * square(2 * pi * freq * t);
        otherwise
            error('generateSignal:InvalidMethod', ...
                'Method must be ''Sine'' or ''Square''.');
    end

    spectrum = abs(fft(signal));
    freqAxis = linspace(0, 1000, length(spectrum));
    rmsValue = rms(signal);
end

Step 3: Test the Function Independently

Before compiling, test the function from the MATLAB command window:

[t, sig, fAx, spec, rmsVal] = generateSignal(50, 1.0, 2, 'Sine');
plot(t, sig);
title(sprintf('RMS = %.4f', rmsVal));

Guidelines for Complex Apps

Example Prompts for Extracting Callbacks

The following prompts demonstrate how to use an AI assistant to help tease apart a .mlapp callback into a clean, standalone MATLAB function.

Prompt A: Identify the Three Zones

Prompt

Here is a callback function from my MATLAB Web App. Please go through it line by line and label each line as one of three zones: (1) UI Read, (2) Algorithm, (3) UI Write. After labeling, list the inputs and outputs that the extracted function will need.

function RunButtonPushed(app, event)
    material = app.MaterialDropDown.Value;
    thickness = app.ThicknessEditField.Value;
    temperature = app.TempSlider.Value;
    includeDefects = app.DefectsCheckBox.Value;

    props = getMaterialProperties(material);
    stress = props.E * thickness * temperature / 1000;
    if includeDefects
        stress = stress * 0.85;
    end
    strain = linspace(0, 0.1, 200);
    stressCurve = stress * (1 - exp(-30 * strain));
    yieldPoint = interp1(stressCurve, strain, 0.9 * max(stressCurve));

    plot(app.UIAxes, strain, stressCurve, 'b-', 'LineWidth', 1.5);
    hold(app.UIAxes, 'on');
    xline(app.UIAxes, yieldPoint, 'r--', 'LineWidth', 1);
    hold(app.UIAxes, 'off');
    title(app.UIAxes, sprintf('%s Stress-Strain Curve', material));
    xlabel(app.UIAxes, 'Strain');
    ylabel(app.UIAxes, 'Stress (MPa)');
    app.YieldPointLabel.Text = sprintf('Yield Point: %.4f', yieldPoint);
    app.MaxStressLabel.Text = sprintf('Max Stress: %.1f MPa', max(stressCurve));
end

Prompt B: Extract and Write the Standalone Function

Prompt

Based on the three-zone analysis above, please extract the Algorithm zone into a standalone MATLAB function. Requirements: (1) No app.* references. (2) Every UI-read value becomes an input argument. (3) Every UI-written value becomes an output argument. (4) Add full documentation. (5) Add input validation. (6) Name it descriptively. Also provide a test snippet.

Prompt C: Handle a Callback with Multiple Plots and Table Output

Prompt

This callback produces two plots and populates a UITable. Please extract it into a standalone function. For the table data, return it as a MATLAB table or cell array that I can later convert to JSON for the front end.

function AnalyzeButtonPushed(app, event)
    data = app.DataTable.Data;
    colNames = app.DataTable.ColumnName;
    filterIdx = app.FilterDropDown.Value;
    smoothWindow = app.SmoothSpinner.Value;

    filtered = data(data(:,1) > filterIdx, :);
    smoothed = movmean(filtered(:,2), smoothWindow);
    residuals = filtered(:,2) - smoothed;
    stats = [mean(residuals), std(residuals), max(abs(residuals))];
    summaryTable = array2table(stats, ...
        'VariableNames', {'Mean', 'StdDev', 'MaxAbs'});

    plot(app.UIAxes1, filtered(:,1), filtered(:,2), 'b-', ...
         filtered(:,1), smoothed, 'r-', 'LineWidth', 1.5);
    legend(app.UIAxes1, 'Raw', 'Smoothed');
    title(app.UIAxes1, 'Signal Analysis');

    bar(app.UIAxes2, residuals);
    title(app.UIAxes2, 'Residuals');

    app.StatsTable.Data = summaryTable;
    app.RMSELabel.Text = sprintf('RMSE: %.4f', std(residuals));
end

Prompt D: Refactor a Callback That Uses Shared State

Prompt

This callback depends on data that was loaded by a separate LoadDataButtonPushed callback and stored in app.LoadedData. I need to make it self-contained so it can run on MATLAB Production Server with no persistent state between calls. Please refactor so rawData is passed as an input argument. Also explain how I should structure this data in the MPS JSON payload.

function ProcessButtonPushed(app, event)
    % Uses app.LoadedData which was set by a different callback
    rawData = app.LoadedData;
    nBins = app.BinsSpinner.Value;
    normalize = app.NormalizeCheckBox.Value;

    if normalize
        rawData = (rawData - mean(rawData)) / std(rawData);
    end
    [counts, edges] = histcounts(rawData, nBins);
    centers = edges(1:end-1) + diff(edges)/2;
    peakVal = max(counts);
    peakBin = centers(counts == peakVal);

    bar(app.UIAxes, centers, counts);
    title(app.UIAxes, 'Distribution');
    app.PeakLabel.Text = sprintf('Peak at %.2f (count: %d)', peakBin(1), peakVal);
end

5. Replacing MATLAB Plots with JavaScript Charts

MATLAB plots need to be replicated on the front end using a JavaScript charting library. The two best options are Chart.js and Plotly.js.

When to Use Which

FeatureChart.jsPlotly.js
Line, bar, scatter, pieExcellentExcellent
Interactive zoom/panPlugin requiredBuilt-in
3D plots, surface plotsNot supportedBuilt-in
Heatmaps, contour plotsLimitedBuilt-in
Bundle size~60 KB~3 MB
Learning curveSimplerMore complex

Rule of thumb: Use Chart.js for standard 2D line/bar/scatter charts. Use Plotly.js if you need 3D surfaces, contours, heatmaps, or advanced interactivity.

Chart.js Example

Include Chart.js from CDN and add a canvas element:

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="signalChart" width="600" height="400"></canvas>

Initialize the chart in JavaScript:

const ctx = document.getElementById('signalChart').getContext('2d');
const signalChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: [],   // Will be populated from API response
        datasets: [{
            label: 'Signal',
            data: [],
            borderColor: 'rgb(0, 114, 189)',  // MATLAB default blue
            borderWidth: 1.5,
            pointRadius: 0,
            fill: false
        }]
    },
    options: {
        responsive: true,
        scales: {
            x: { title: { display: true, text: 'Time (s)' } },
            y: { title: { display: true, text: 'Amplitude' } }
        }
    }
});

Plotly.js Example

<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="signalPlot" style="width:600px;height:400px;"></div>
const trace = {
    x: [],  // Time vector from API
    y: [],  // Signal data from API
    type: 'scatter',
    mode: 'lines',
    name: 'Signal',
    line: { color: 'rgb(0, 114, 189)', width: 1.5 }
};
Plotly.newPlot('signalPlot', [trace], {
    title: 'Generated Signal',
    xaxis: { title: 'Time (s)' },
    yaxis: { title: 'Amplitude' }
});

MATLAB Default Color Order

Use these colors to give charts a familiar MATLAB feel:

LineRGBHex
1st(0, 0.4470, 0.7410)#0072BD
2nd(0.8500, 0.3250, 0.0980)#D95319
3rd(0.9290, 0.6940, 0.1250)#EDB120
4th(0.4940, 0.1840, 0.5560)#7E2F8E
5th(0.4660, 0.6740, 0.1880)#77AC30
6th(0.3010, 0.7450, 0.9330)#4DBEEE
7th(0.6350, 0.0780, 0.1840)#A2142F

6. Handling Input and Output Data

The data flow needs to be clearly mapped: HTML form fields → JSON input → MATLAB function arguments → MATLAB return values → JSON output → chart data.

Input: HTML Fields to Function Arguments

For each input argument of your extracted MATLAB function, there must be a corresponding HTML element:

MATLAB function signature:
  generateSignal(freq, amp, duration, method)

Mapping:
  freq     <- <input type="number" id="freqInput" value="50">
  amp      <- <input type="number" id="ampInput" value="1.0">
  duration <- <input type="range" id="durationSlider" min="0.1" max="5">
  method   <- <select id="methodSelect">
                <option value="Sine">Sine</option>
                <option value="Square">Square</option>
              </select>

Gather these into a JavaScript object:

function getInputs() {
    return {
        freq:     parseFloat(document.getElementById('freqInput').value),
        amp:      parseFloat(document.getElementById('ampInput').value),
        duration: parseFloat(document.getElementById('durationSlider').value),
        method:   document.getElementById('methodSelect').value
    };
}

Output: Function Returns to Chart Data

Your MATLAB function returns multiple outputs. These arrive in the Production Server JSON response as lhs (left-hand side) outputs:

lhs[0].mwdata -> t         -> Chart X-axis (time domain)
lhs[1].mwdata -> signal    -> Chart Y-axis (time domain)
lhs[2].mwdata -> freqAxis  -> Chart X-axis (frequency domain)
lhs[3].mwdata -> spectrum  -> Chart Y-axis (frequency domain)
lhs[4].mwdata -> rmsValue  -> Display in a label or badge

7. Constructing the HTTP POST to MATLAB Production Server

MATLAB Production Server exposes deployed functions as REST endpoints. The RESTful API specification can be found at the MPS REST API documentation and the JSON schema is documented at JSON representation of MATLAB data types.

Endpoint URL Pattern

http://<server>:<port>/<archiveName>/<functionName>

Example:
POST http://localhost:9910/signalApp/generateSignal

JSON Request Schema

Production Server expects a specific JSON structure. Each input argument is an element in the rhs (right-hand side) array. The nargout field tells MATLAB how many output arguments to return:

{
    "nargout": 5,
    "rhs": [
        { "mwdata": [50],     "mwsize": [1, 1], "mwtype": "double" },
        { "mwdata": [1.0],    "mwsize": [1, 1], "mwtype": "double" },
        { "mwdata": [2],      "mwsize": [1, 1], "mwtype": "double" },
        { "mwdata": ["Sine"], "mwsize": [1, 4], "mwtype": "char"   }
    ]
}

Field Descriptions

Handling Different Data Types

Scalar double:

{ "mwdata": [3.14], "mwsize": [1, 1], "mwtype": "double" }

Row vector (1x5 double):

{ "mwdata": [1, 2, 3, 4, 5], "mwsize": [1, 5], "mwtype": "double" }

Matrix (2x3 double) -- stored column-major:

{ "mwdata": [1, 4, 2, 5, 3, 6], "mwsize": [2, 3], "mwtype": "double" }

Note: MATLAB stores matrices column-major, so [1 2 3; 4 5 6] flattens as [1, 4, 2, 5, 3, 6] (down columns first).

String / char array:

{ "mwdata": ["Sine"], "mwsize": [1, 4], "mwtype": "char" }

If you are just passing in a few arguments and don't wish to specify the size or type, you can use a simplified payload:

{"nargout": 1, "rhs": [308.0, 2.4, 3.5, "Step"]}

Example Prompts

Prompt A: Capture Inputs, Build the JSON Payload, and Call the API

Prompt

I have the following MATLAB function deployed to MATLAB Production Server as an archive called signalApp. [Include function signature with inputs/outputs documented.] My HTML form has these elements: [list elements with IDs]. Please generate JavaScript that reads values, validates them, constructs the MPS JSON payload with correct rhs array (mwdata, mwsize, mwtype), sets nargout, POSTs to the endpoint, includes error handling, and returns the parsed lhs array. Also show me the exact JSON payload for sample inputs so I can verify with cURL.

Prompt B: Handle the API Response and Render Charts

Prompt

My JavaScript calculate() function calls generateSignal on MATLAB Production Server and gets back a response with lhs array. [Describe structure.] Please generate JavaScript that extracts each output from lhs, initializes Chart.js charts with MATLAB default colors, updates them when new results arrive, displays scalar values, and downsamples large arrays. Also show the Plotly.js equivalent as a commented-out alternative.

8. Compiling and Deploying to MATLAB Production Server

Step 1: Prepare the Function

Ensure your standalone function works correctly from the MATLAB command window with no dependencies on app.* objects, UI components, or desktop features. All helper functions or data files it depends on must be on the MATLAB path.

Step 2: Open the Production Server Compiler

In MATLAB, run:

productionServerCompiler

Or navigate to the Apps tab and select Production Server Compiler.

Step 3: Configure the Archive

  1. Click Add Exported Function and select your .m file (e.g., generateSignal.m).
  2. If your function depends on other .m files, toolboxes, or data files, add them under Files required for your function to run.
  3. Set the Archive Name (e.g., signalApp). This becomes part of the API URL.

Step 4: Package the Archive

Click Package. This produces a .ctf file (e.g., signalApp.ctf) in the output directory. Alternatively, compile from the command line:

compiler.build.productionServerArchive('generateSignal.m', 'ArchiveName', 'signalApp')

Step 5: Deploy to MATLAB Production Server

Copy the .ctf file into the Production Server auto_deploy directory:

<MPS_INSTALL>/auto_deploy/signalApp.ctf

Production Server monitors this folder and automatically loads new or updated archives.

9. Calling the MATLAB Production Server API from JavaScript

Here is a complete JavaScript function that gathers inputs, constructs the payload, calls the API, and updates the chart:

async function calculate() {
    // 1. Gather inputs from the HTML form
    const freq     = parseFloat(document.getElementById('freqInput').value);
    const amp      = parseFloat(document.getElementById('ampInput').value);
    const duration = parseFloat(document.getElementById('durationSlider').value);
    const method   = document.getElementById('methodSelect').value;

    // 2. Construct the Production Server JSON payload
    const payload = {
        nargout: 5,
        rhs: [
            { mwdata: [freq],     mwsize: [1, 1],             mwtype: "double" },
            { mwdata: [amp],      mwsize: [1, 1],             mwtype: "double" },
            { mwdata: [duration], mwsize: [1, 1],             mwtype: "double" },
            { mwdata: [method],   mwsize: [1, method.length], mwtype: "char"   }
        ]
    };

    // 3. POST to MATLAB Production Server
    const MPS_URL = '/signalApp/generateSignal';
    try {
        const response = await fetch(MPS_URL, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        });
        if (!response.ok) throw new Error(`MPS returned HTTP ${response.status}`);
        const result = await response.json();

        // 4. Extract output data from the lhs array
        const t        = result.lhs[0].mwdata;
        const signal   = result.lhs[1].mwdata;
        const freqAxis = result.lhs[2].mwdata;
        const spectrum = result.lhs[3].mwdata;
        const rmsValue = result.lhs[4].mwdata[0];

        // 5. Update the Chart.js chart
        signalChart.data.labels = t;
        signalChart.data.datasets[0].data = signal;
        signalChart.update();

        // 6. Update the RMS display
        document.getElementById('rmsDisplay').textContent =
            `RMS: ${rmsValue.toFixed(4)}`;

    } catch (error) {
        console.error('API call failed:', error);
        alert('Calculation failed. Check the console for details.');
    }
}

document.getElementById('calculateBtn').addEventListener('click', calculate);

Handling CORS

If the front end is served from a different origin than Production Server (different host or port), you will encounter CORS errors. You have three options:

  1. Serve the front end from MATLAB Production Server itself (see Section 11) -- avoids CORS entirely since everything is same-origin.
  2. Configure a reverse proxy (e.g., NGINX or Apache) that serves both the front end and proxies API calls to MATLAB Production Server.
  3. Enable CORS on MATLAB Production Server by configuring the cors-allowed-origins property in main_config (available in newer versions).

10. Handling the Response and Debugging with Postman/cURL

Understanding the MATLAB Production Server Response Format

A successful response has HTTP status 200 and a JSON body containing an lhs (left-hand side) array. Each element corresponds to one output argument:

{
    "lhs": [
        { "mwdata": [0, 0.001, 0.002, 0.003], "mwsize": [1, 4], "mwtype": "double" },
        { "mwdata": [0, 0.309, 0.588, 0.809], "mwsize": [1, 4], "mwtype": "double" },
        { "mwdata": [42.5],                    "mwsize": [1, 1], "mwtype": "double" }
    ]
}

Key points:

Debugging with cURL

Test your deployed function directly from the command line:

curl -X POST http://localhost:9910/signalApp/generateSignal \
  -H "Content-Type: application/json" \
  -d '{
    "nargout": 5,
    "rhs": [
        {"mwdata": [50],     "mwsize": [1,1], "mwtype": "double"},
        {"mwdata": [1.0],    "mwsize": [1,1], "mwtype": "double"},
        {"mwdata": [0.05],   "mwsize": [1,1], "mwtype": "double"},
        {"mwdata": ["Sine"], "mwsize": [1,4], "mwtype": "char"}
    ]
  }'

Pipe through jq for formatted output:

curl -s -X POST ... | jq .
curl -s -X POST ... | jq '.lhs[] | {mwtype, mwsize}'

Debugging with Postman

  1. Create a new POST request.
  2. Set the URL to your endpoint.
  3. Under the Headers tab, add Content-Type: application/json.
  4. Under the Body tab, select raw and paste the JSON payload.
  5. Click Send and inspect the response body.

Common Error Responses

HTTP StatusMeaningWhat to Check
404Archive or function not foundIs the .ctf deployed? Is the URL path correct?
400Bad request / invalid JSONCheck JSON syntax, mwtype, mwsize consistency.
500MATLAB runtime errorCheck MPS logs in <MPS_INSTALL>/log/main.log.

11. Deploying the Front End

You have two primary options for serving the HTML/CSS/JS front end.

Option A: Use MATLAB Production Server Built-In Static File Serving

MATLAB Production Server can serve static files directly, which means your front end and API share the same origin -- no CORS configuration needed. Use this approach for simplicity and prototyping/test. We do not recommend this for a production deployment.

Step 1: Enable Static File Serving in main_config

Open the Production Server configuration file at <MPS_INSTALL>/config/main_config and add or modify:

--enable-static-folders true
--static-folders-root /opt/mps/static

Step 2: Organize Your Files

/opt/mps/static/
+-- index.html
+-- css/
|   +-- styles.css
+-- js/
|   +-- app.js
+-- images/
    +-- logo.png

Step 3: Access the App

After restarting Production Server:

http://localhost:9910/index.html                     (front end)
http://localhost:9910/signalApp/generateSignal        (API)

Since both are on the same origin, there are no CORS issues.

MATLAB Production Server Configuration Reference

--http 9910                       # Port MPS listens on (default 9910)
--https 9920                      # HTTPS port
--ssl-cert /path/to/cert.pem     # HTTPS certificate
--ssl-key /path/to/key.pem       # HTTPS private key
--num-workers 4                   # Number of MATLAB workers
--request-timeout 120             # Request timeout (seconds)

Option B: Use a Separate Web Server

If you need more control (custom routing, authentication, SSR, integration with an existing site), serve the front end from a dedicated web server and proxy API calls to Production Server.

Nginx Example Configuration

server {
    listen 80;
    server_name myapp.example.com;

    root /var/www/myapp;
    index index.html;

    location /api/ {
        proxy_pass http://localhost:9910/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 120s;
    }
}

Simple Development Server

For local development and testing:

cd /path/to/your/web/files
python3 -m http.server 8080

12. Summary and Best Practices

Workflow Checklist

  1. Screenshot every state and interaction of the original .mlapp.
  2. Extract the algorithmic logic into a standalone MATLAB function with clear inputs and outputs.
  3. Test the function from the MATLAB command window.
  4. Build the HTML/CSS/JS front end, matching the original layout.
  5. Replace MATLAB plots with Chart.js or Plotly.js.
  6. Compile the function into a .ctf archive using the Production Server Compiler.
  7. Deploy the .ctf to the MATLAB Production Server auto_deploy folder.
  8. Test the API with cURL or Postman before wiring up the front end.
  9. Connect the front end to the API using fetch().
  10. Deploy the front end via MATLAB Production Server static serving or an external web server.

Best Practices

13. Useful Tools