<- Back to Blog

How to Start a Rust App on Login in macOS

A deep dive into the challenges of starting Rust apps on login in macOS, comparing Tauri's autostart plugin with a native approach using smappservice-rs.

iason-p
Iason P. ·
How to Start a Rust App on Login in macOS

Contents#

Introduction#

At Hopp, our goal is to make the remote pair programming experience as seamless as possible. For that, our desktop app needs to be ready the moment you want to hop on a code pairing call—so it needs to start automatically when the user logs in.

Hopp is built with Tauri, so the natural step was to use Tauri's autostart plugin. While it worked as expected, we noticed a few limitations that didn't fit our vision for a polished, near-native user experience.

That's why we built smappservice-rs: a Rust wrapper for macOS's ServiceManagement framework.

In this post, I'll share why we made this decision, what you get with our library, and how it helps us deliver a better experience for Hopp macOS users.

Using Tauri Autostart Plugin for Rust Apps on macOS#

Tauri's autostart plugin works across Windows, macOS, and Linux, allowing your app to start automatically at system startup. Under the hood, it uses the auto-launch crate, which is the Rust equivalent of node-auto-launch.

On macOS, the plugin supports two methods for starting your app on login:

  • AppleScript
  • LaunchAgent plist file

AppleScript

The AppleScript method executes a script that instructs System Events to add or remove a login item for your app. When this method is used, the user will see two pop-ups:

  1. A permission request for access to System Events.
    System events permission popup
    System events permission popup
  2. A notification that the app was added to the login items by System Events.
    System events notification
    System events notification

We see two issues with this approach:

  • It requires two pop-ups, instead of just one when using a native API.
  • It isn't entirely clear from the pop-ups which app is being added to the login items.

Ditch the frustrating "Can you see my screen?" dance.

Code side-by-side, remotely.

Join our waiting list

LaunchAgent

This method adds a plist file to the user's Library/LaunchAgents directory. When this method is used, the user receives a notification.

LaunchAgent notification
LaunchAgent notification

While there is only one notification, the same issue from the AppleScript method remains: the notification does not specify which app was added to the login items. (This is configurable and was added recently in the implementation.)

Another issue with the LaunchAgent method is that the user has no straightforward way to remove the app from starting on login. The only option is to manually delete the plist file. Even if the app is uninstalled, the entry may remain in the "Allow in the Background" list.

While both methods successfully start your app when the user logs in, they fall short of the seamless, native experience we want to deliver with Hopp.

Native macOS Login Items with smappservice-rs in Rust#

smappservice-rs is a Rust wrapper around the macOS ServiceManagement framework. The ServiceManagement framework in macOS provides a way for applications to manage system services. With it, you can:

  • Register your application as a login item
  • Register and manage launch agents and daemons from the application bundle
  • Check the status of registered services

The main advantage of using smappservice-rs instead of auto-launch is that it leverages the native macOS API to manage login items, resulting in a more polished and integrated user experience.

For example, when you use smappservice-rs to register your app as a login item, the user will see a single notification that states which app was added to the login items.

SMAppService notification
SMAppService notification

Another benefit is that if a launch agent is registered, it isn't installed in ~/Library/LaunchAgents, but instead comes from the app bundle. This means it'll be removed automatically when the app is uninstalled, keeping the system clean and user-friendly.

How to register a Rust app as a login item with smappservice-rs#

To register your Rust app as a login item using smappservice-rs, you need to

use smappservice_rs::{AppService, ServiceType};

let app_service = AppService::new(ServiceType::MainApp);
match app_service.register() {
    Ok(()) => println!("App registered successfully!"),
    Err(e) => eprintln!("Failed to register app: {}", e),
}

You can also unregister the app as a login item with:

use smappservice_rs::{AppService, ServiceType};

let app_service = AppService::new(ServiceType::MainApp);
match app_service.unregister() {
    Ok(()) => println!("App unregistered successfully!"),
    Err(e) => eprintln!("Failed to unregister app: {}", e),
}

Finally you can check if the app is registered as a login item with:

use smappservice_rs::{AppService, ServiceType, ServiceStatus};

let app_service = AppService::new(ServiceType::MainApp);
let status = app_service.status();

if status == ServiceStatus::RequiresApproval {
    AppService::open_system_settings_login_items();
}

You can read more about the features and usage of smappservice-rs in the documentation.

Ditch the frustrating "Can you see my screen?" dance.

Code side-by-side, remotely.

Join our waiting list

Conclusion#

Choosing the right approach for starting a Rust app on login is essential for delivering a native and seamless user experience on macOS. While Tauri's autostart plugin offers a cross-platform solution, its macOS implementation comes with trade-offs—such as less clear notifications and limited user control—that didn't align with our goals for Hopp.

By developing smappservice-rs, we were able to leverage the native ServiceManagement framework, resulting in a more integrated and user-friendly experience. This approach ensures that login items are managed transparently and cleanly, both for users and the system.

If you have any questions or think we missed something, feel free to reach out on X/Twitter or email me at iason@gethopp.app.

smappservice
login-items
launch-agents
launch-daemons

Join the waitlist

Get early access to the fastest pair programming tool built for technical teams. Be the first to experience sub-millisecond latency, native performance, and get exclusive pricing when we go live.

Be among the first to try Hopp — join the waitlist today