---
title: "DropletPreferencesService, DroppyKit"
description: "Persistent, droplet-scoped settings."
canonical: "https://getdroppy.app/docs/droppykit/api/droplet-preferences-service"
last-updated: "2026-09-09"
---

# DropletPreferencesService

Persistent, droplet-scoped settings.

`@MainActor protocol DropletPreferencesService : AnyObject`

Keys are automatically namespaced to `droplet.<your-id>.<key>` in Droppy's own preferences domain, so two droplets can both store `"interval"` without colliding, and a droplet can never read or overwrite a host preference or another droplet's. That namespacing is why [`DropletID`](https://getdroppy.app/docs/droppykit/api/droplet-id) forbids `.` — see the charset note on [`isValid(_:)`](https://getdroppy.app/docs/droppykit/api/droplet-id#is-valid).

Settings survive being disabled and re-enabled, and survive an update. Removing a droplet does not erase them either, so a user who removes and reinstalls finds their configuration intact.

## Properties

### didChange

`@MainActor var didChange: AnyPublisher<String, Never> { get }`

Fires after any of this droplet's keys changes, including changes made from the droplet's own settings pane.

## Methods

### hasValue(forKey:)

`@MainActor func hasValue(forKey key: String) -> Bool`

Whether the key currently holds a value.

### removeAll()

`@MainActor func removeAll()`

Removes every key this droplet has written.

### setValue(_:forKey:)

`@MainActor func setValue<Value>(_ value: Value?, forKey key: String) where Value : Decodable, Value : Encodable`

Writes a value. Pass `nil` to clear the key.

### value(forKey:as:)

`@MainActor func value<Value>(forKey key: String, as type: Value.Type) -> Value? where Value : Decodable, Value : Encodable`

Reads a stored value, or `nil` when the key was never written.

### value(forKey:default:)

`@MainActor func value<Value>(forKey key: String, default defaultValue: Value) -> Value where Value : Decodable, Value : Encodable`

Reads a value, falling back to `defaultValue` when the key is unset.
