How do I setup auto update for Cursor on Linux (Ubuntu)?

I downloaded the cursor*.AppImage file and run it to open the editor. Will it auto-update? If not, how do I set it up?

1 Like

Hi @evgenyneu

Here’s some information on how to enable updates in Linux.

1 Like

Seems that cursor does not prioritize linux users so all updates are delayed, missing, and not integrated with the OS. This led me to windsurf which is also a vscode fork but native for linux.

Check out a thread about this issue: Please improve Linux support

1 Like

Well these instructions did not work. Appreciate the effort though. It is shameful that the Cursor team cannot develop a proper install/update process for Cursor in Linux.

It works but needed a small tweak in the update-cursor.sh script, the url used in the tutorial doesn’t work anymore so replaced it with the new url and the new url doesn’t directly give you the AppImage, it returns a JSON with the actual download URL inside it. So I had to update the script to first fetch that URL using. Also, make sure both are installed (sudo apt install curl jq if needed).

#!/bin/bash

APPDIR=~/Applications/cursor
APPIMAGE_URL_API="https://www.cursor.com/api/download?platform=linux-x64&releaseTrack=stable"

# Create the app directory if it doesn't exist
mkdir -p "$APPDIR"

# Fetch the actual AppImage URL from the API
echo "Fetching latest Cursor AppImage URL..."
DOWNLOAD_URL=$(curl -s "$APPIMAGE_URL_API" | jq -r '.downloadUrl')

# Check if we got a valid URL
if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then
  echo "Error: Failed to retrieve download URL from Cursor API."
  exit 1
fi

# Download and make it executable
echo "Downloading Cursor AppImage from $DOWNLOAD_URL..."
wget -O "$APPDIR/cursor.AppImage" "$DOWNLOAD_URL"
chmod +x "$APPDIR/cursor.AppImage"

echo "Cursor AppImage installed at $APPDIR/cursor.AppImage"
3 Likes

This is great - I made some adjustments to follow the redirect from cursor as well as check the version instead of downloading the newest image every time regardless of updates, if any interest.

#!/bin/bash

APPDIR=~/Applications/cursor
APPIMAGE_URL_API="https://www.cursor.com/api/download?platform=linux-x64&releaseTrack=stable"
VERSION_FILE="$APPDIR/current_version.txt"

# Create the app directory if it doesn't exist
mkdir -p "$APPDIR"

echo "Checking for Cursor updates..."

# Fetch the latest release info from the API
API_RESPONSE=$(curl -sL --connect-timeout 30 --max-time 60 "$APPIMAGE_URL_API")

if [ $? -ne 0 ] || [ -z "$API_RESPONSE" ]; then
    echo "Error: Failed to connect to Cursor API."
    exit 1
fi

# Extract download URL and version info
DOWNLOAD_URL=$(echo "$API_RESPONSE" | jq -r '.downloadUrl' 2>/dev/null)
LATEST_VERSION=$(echo "$API_RESPONSE" | jq -r '.version // .tag_name // "unknown"' 2>/dev/null)

if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then
    echo "Error: Failed to retrieve download URL from Cursor API."
    exit 1
fi

# If we can't get version info from API, use URL as version identifier
if [[ -z "$LATEST_VERSION" || "$LATEST_VERSION" == "null" || "$LATEST_VERSION" == "unknown" ]]; then
    LATEST_VERSION=$(echo "$DOWNLOAD_URL" | grep -o '/[^/]*\.AppImage' | sed 's|/||' | sed 's|\.AppImage||')
fi

echo "Latest version: $LATEST_VERSION"

# Check current version
CURRENT_VERSION=""
if [ -f "$VERSION_FILE" ]; then
    CURRENT_VERSION=$(cat "$VERSION_FILE")
    echo "Current version: $CURRENT_VERSION"
fi

# Check if we need to update
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ] && [ -f "$APPDIR/cursor.AppImage" ]; then
    echo "Cursor is already up to date (version: $CURRENT_VERSION)"
    exit 0
fi

echo "New version available! Updating from '$CURRENT_VERSION' to '$LATEST_VERSION'"

# Download the new version
echo "Downloading Cursor AppImage from $DOWNLOAD_URL..."

if curl -L --fail --progress-bar -o "$APPDIR/cursor.AppImage.tmp" "$DOWNLOAD_URL"; then
    if [ -s "$APPDIR/cursor.AppImage.tmp" ]; then
        # Backup old version if it exists
        if [ -f "$APPDIR/cursor.AppImage" ]; then
            mv "$APPDIR/cursor.AppImage" "$APPDIR/cursor.AppImage.backup"
        fi
        
        # Install new version
        mv "$APPDIR/cursor.AppImage.tmp" "$APPDIR/cursor.AppImage"
        chmod +x "$APPDIR/cursor.AppImage"
        
        # Save version info
        echo "$LATEST_VERSION" > "$VERSION_FILE"
        
        echo "✅ Cursor successfully updated to version $LATEST_VERSION"
        echo "File size: $(ls -lh "$APPDIR/cursor.AppImage" | awk '{print $5}')"
        
        # Clean up backup after successful update
        rm -f "$APPDIR/cursor.AppImage.backup"
    else
        echo "Error: Downloaded file is empty"
        rm -f "$APPDIR/cursor.AppImage.tmp"
        exit 1
    fi
else
    echo "Error: Failed to download Cursor AppImage"
    rm -f "$APPDIR/cursor.AppImage.tmp"
    exit 1
fi

Updated install-cursor.sh

#!/bin/bash
set -euo pipefail

# --- Config ---
API_URL="https://cursor.com/api/download?platform=linux-x64&releaseTrack=stable"
ICON_URL="https://avatars.githubusercontent.com/u/126759922"
INSTALL_DIR="$HOME/Applications/cursor"
CURSOR_APP_IMAGE="$INSTALL_DIR/cursor.AppImage"
CURSOR_ICON="$INSTALL_DIR/cursor-icon.png"
DESKTOP_FILE="$HOME/.local/share/applications/cursor.desktop"
WRAPPER_SYS="/usr/local/bin/cursor"
WRAPPER_USER="$HOME/.local/bin/cursor"

# --- Helpers ---
need_cmd() {
  command -v "$1" >/dev/null 2>&1 || { echo "Missing dependency: $1" >&2; exit 1; }
}

# --- Checks ---
need_cmd curl
need_cmd jq
need_cmd wget

# --- Fetch latest download URL ---
echo "Fetching latest Cursor release info..."
json=$(curl -fsSL "$API_URL")
download_url=$(echo "$json" | jq -r '.downloadUrl')

if [[ -z "$download_url" || "$download_url" == "null" ]]; then
  echo "Failed to retrieve downloadUrl from API: $API_URL" >&2
  exit 1
fi

# --- Prepare directories ---
mkdir -p "$INSTALL_DIR"

# --- Download AppImage ---
echo "Downloading Cursor AppImage from:"
echo "  $download_url"
# show a progress bar; follow redirects if any
wget --progress=bar:force:noscroll -O "$CURSOR_APP_IMAGE" "$download_url"
chmod +x "$CURSOR_APP_IMAGE"
echo "✔ AppImage saved to $CURSOR_APP_IMAGE"

# --- Create launcher wrapper that adds --no-sandbox ---
create_wrapper() {
  local path="$1"
  mkdir -p "$(dirname "$path")"
  cat > "$path" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
APPIMAGE_PATH="__APPIMAGE_PATH__"
exec "$APPIMAGE_PATH" --no-sandbox "$@"
EOF
  # Inject the real AppImage path safely
  sed -i "s#__APPIMAGE_PATH__#$(printf '%q' "$CURSOR_APP_IMAGE")#g" "$path"
  chmod +x "$path"
}

EXEC_PATH=""
if sudo -n true 2>/dev/null; then
  echo "Creating system-wide wrapper at $WRAPPER_SYS (using sudo)..."
  tmpfile="$(mktemp)"
  create_wrapper "$tmpfile"
  sudo mv "$tmpfile" "$WRAPPER_SYS"
  EXEC_PATH="$WRAPPER_SYS"
else
  echo "No passwordless sudo detected. Attempting sudo for system-wide wrapper..."
  if sudo true; then
    echo "Creating system-wide wrapper at $WRAPPER_SYS..."
    tmpfile="$(mktemp)"
    create_wrapper "$tmpfile"
    sudo mv "$tmpfile" "$WRAPPER_SYS"
    EXEC_PATH="$WRAPPER_SYS"
  else
    echo "Falling back to user wrapper at $WRAPPER_USER"
    create_wrapper "$WRAPPER_USER"
    EXEC_PATH="$WRAPPER_USER"
  fi
fi
echo "✔ Wrapper created at $EXEC_PATH (adds --no-sandbox)"

# --- Download icon (best-effort) ---
echo "Fetching icon..."
wget -q -O "$CURSOR_ICON" "$ICON_URL" || echo "Icon download failed; continuing."

# --- Create .desktop entry ---
mkdir -p "$(dirname "$DESKTOP_FILE")"
cat > "$DESKTOP_FILE" <<EOF
[Desktop Entry]
Name=Cursor
Exec=$EXEC_PATH %U
TryExec=$EXEC_PATH
Icon=$CURSOR_ICON
Type=Application
Categories=Utility;Development;
Terminal=false
StartupNotify=true
EOF
echo "✔ Desktop entry created at $DESKTOP_FILE"

# --- Refresh desktop database / menus (best-effort) ---
if command -v update-desktop-database >/dev/null 2>&1; then
  update-desktop-database "$HOME/.local/share/applications" || true
fi
if command -v xdg-desktop-menu >/dev/null 2>&1; then
  xdg-desktop-menu forceupdate || true
fi

echo
echo "✅ Cursor installed."
echo "   AppImage: $CURSOR_APP_IMAGE"
echo "   Launcher: $EXEC_PATH (always runs with --no-sandbox)"
echo "   Menu entry: $DESKTOP_FILE"
echo
echo "You should now find 'Cursor' in your applications menu."
echo "Or run: $(printf '%q' "$EXEC_PATH")"

Updated update-cursor.sh

#!/bin/bash
set -euo pipefail

API_URL="https://cursor.com/api/download?platform=linux-x64&releaseTrack=stable"
INSTALL_DIR="$HOME/Applications/cursor"
CURSOR_APP_IMAGE="$INSTALL_DIR/cursor.AppImage"

# Check dependencies
for cmd in curl jq wget; do
  command -v "$cmd" >/dev/null 2>&1 || {
    echo "Missing required command: $cmd" >&2
    exit 1
  }
done

# Fetch latest release info
echo "Checking for updates..."
json=$(curl -fsSL "$API_URL")
download_url=$(echo "$json" | jq -r '.downloadUrl')
version=$(echo "$json" | jq -r '.version')

if [[ -z "$download_url" || "$download_url" == "null" ]]; then
  echo "Failed to retrieve download URL from $API_URL" >&2
  exit 1
fi

echo "Latest Cursor version: $version"
echo "Downloading from: $download_url"

# Ensure install dir exists
mkdir -p "$INSTALL_DIR"

# Download to a temp file first
tmpfile=$(mktemp)
wget --progress=bar:force:noscroll -O "$tmpfile" "$download_url"

# Replace old AppImage
mv "$tmpfile" "$CURSOR_APP_IMAGE"
chmod +x "$CURSOR_APP_IMAGE"

echo "✔ Cursor updated to version $version"
echo "Executable: $CURSOR_APP_IMAGE"
1 Like

Native .deb and RPM releases are now available! :tada:

Get it from Downloads | Cursor - The AI Code Editor

1 Like

don’t blame them. may be they are using Cursor to develop that

1 Like

The issue has been fixed! Cursor AppImage automatically updates for me.