diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# Version 0.3
+
+* The `segment`, `key`, `value` and `message` functions are now methods of the
+  new `ToSegment`, `ToKey`, `ToValue` and `ToMessage` classes.  Identity
+  instances, as well as instances for `String`, lazy `Text` and strict `Text`,
+  have been introduced for these classes.
+
+
 # Version 0.2
 
 * BREAKING CHANGE: `Segment`, `Key`, `Value` and `Message` don't strip
diff --git a/df1.cabal b/df1.cabal
--- a/df1.cabal
+++ b/df1.cabal
@@ -1,5 +1,5 @@
 name: df1
-version: 0.2
+version: 0.3
 author: Renzo Carbonara
 maintainer: renλren.zone
 copyright: Renzo Carbonara 2016-2018
diff --git a/lib/Df1.hs b/lib/Df1.hs
--- a/lib/Df1.hs
+++ b/lib/Df1.hs
@@ -29,10 +29,10 @@
    T.Log(Log, log_time, log_level, log_path, log_message)
  , T.Level(Debug, Info, Notice, Warning, Error, Critical, Alert, Emergency)
  , T.Path(Attr, Push)
- , T.Segment, T.unSegment, T.segment
- , T.Key, T.unKey, T.key
- , T.Value, T.unValue, T.value
- , T.Message, T.unMessage, T.message
+ , T.Segment, T.unSegment, T.ToSegment(segment)
+ , T.Key, T.unKey, T.ToKey(key)
+ , T.Value, T.unValue, T.ToValue(value)
+ , T.Message, T.unMessage, T.ToMessage(message)
    -- * Parsing
  , P.parse
    -- * Rendering
diff --git a/lib/Df1/Types.hs b/lib/Df1/Types.hs
--- a/lib/Df1/Types.hs
+++ b/lib/Df1/Types.hs
@@ -1,17 +1,20 @@
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeSynonymInstances #-}
 
 module Df1.Types
  ( Log(Log, log_time, log_level, log_path, log_message)
  , Level(Debug, Info, Notice, Warning, Error, Critical, Alert, Emergency)
  , Path(Attr, Push)
- , Segment, unSegment, segment
- , Key, unKey, key
- , Value, unValue, value
- , Message, unMessage, message
+ , Segment, unSegment, ToSegment(segment)
+ , Key, unKey, ToKey(key)
+ , Value, unValue, ToValue(value)
+ , Message, unMessage, ToMessage(message)
  ) where
 
 import Data.Semigroup (Semigroup((<>)))
 import Data.Sequence as Seq
+import qualified Data.Text as T
 import qualified Data.Text.Lazy as TL
 import Data.String (IsString(fromString))
 import qualified Data.Time.Clock.System as Time
@@ -50,23 +53,19 @@
 -- \"foo\" :: 'Message'
 -- @
 --
--- Otherwise, you can use 'fromString' or the 'message' function.
+-- Otherwise, you can use 'fromString' or 'message'.
 --
 -- Notice that @\"\" :: 'Message'@ is acceptable, and will be correctly rendered
 -- and parsed back.
 newtype Message = Message TL.Text
   deriving (Eq, Show)
 
-message :: TL.Text -> Message
-message = Message
-{-# INLINE message #-}
-
 unMessage :: Message -> TL.Text
 unMessage = \(Message x) -> x
 {-# INLINE unMessage #-}
 
 instance IsString Message where
-  fromString = message . TL.pack
+  fromString = message
   {-# INLINE fromString #-}
 
 instance Semigroup Message where
@@ -79,6 +78,46 @@
   mappend (Message a) (Message b) = Message (mappend a b)
   {-# INLINE mappend #-}
 
+-- | Convert an arbitrary type to a 'Message'.
+--
+-- You are encouraged to create custom 'ToMessage' instances for your types
+-- making sure you avoid rendering sensitive details such as passwords, so that
+-- they don't accidentally end up in logs.
+--
+-- Any characters that need to be escaped for rendering will be automatically
+-- escaped at rendering time. You don't need to escape them here.
+class ToMessage a where
+  message :: a -> Message
+
+-- | Identity.
+instance ToMessage Message where
+  message = id
+  {-# INLINE message #-}
+
+-- |
+-- @
+-- x :: 'TL.Text' == 'unMessage' ('message' x)
+-- @
+instance ToMessage TL.Text where
+  message = Message
+  {-# INLINE message #-}
+
+-- |
+-- @
+-- x :: 'T.Text' == 'TL.toStrict' ('unMessage' ('message' x))
+-- @
+instance ToMessage T.Text where
+  message = Message . TL.fromStrict
+  {-# INLINE message #-}
+
+-- |
+-- @
+-- x :: 'String' == 'TL.unpack' ('unMessage' ('message' x))
+-- @
+instance ToMessage String where
+  message = Message . TL.pack
+  {-# INLINE message #-}
+
 --------------------------------------------------------------------------------
 
 -- | Importance of the logged message.
@@ -127,23 +166,19 @@
 -- \"foo\" :: 'Segment'
 -- @
 --
--- Otherwise, you can use 'fromString' or the 'segment' function.
+-- Otherwise, you can use 'fromString' or 'segment'.
 --
 -- Notice that @\"\" :: 'Segment'@ is acceptable, and will be correctly rendered
 -- and parsed back.
 newtype Segment = Segment TL.Text
   deriving (Eq, Show)
 
-segment :: TL.Text -> Segment
-segment = Segment
-{-# INLINE segment #-}
-
 unSegment :: Segment -> TL.Text
 unSegment = \(Segment x) -> x
 {-# INLINE unSegment #-}
 
 instance IsString Segment where
-  fromString = segment . TL.pack
+  fromString = segment
   {-# INLINE fromString #-}
 
 instance Semigroup Segment where
@@ -156,6 +191,46 @@
   mappend (Segment a) (Segment b) = Segment (mappend a b)
   {-# INLINE mappend #-}
 
+-- | Convert an arbitrary type to a 'Segment'.
+--
+-- You are encouraged to create custom 'ToSegment' instances for your types
+-- making sure you avoid rendering sensitive details such as passwords, so that
+-- they don't accidentally end up in logs.
+--
+-- Any characters that need to be escaped for rendering will be automatically
+-- escaped at rendering time. You don't need to escape them here.
+class ToSegment a where
+  segment :: a -> Segment
+
+-- | Identity.
+instance ToSegment Segment where
+  segment = id
+  {-# INLINE segment #-}
+
+-- |
+-- @
+-- x :: 'TL.Text' == 'unSegment' ('segment' x)
+-- @
+instance ToSegment TL.Text where
+  segment = Segment
+  {-# INLINE segment #-}
+
+-- |
+-- @
+-- x :: 'T.Text' == 'TL.toStrict' ('unSegment' ('segment' x))
+-- @
+instance ToSegment T.Text where
+  segment = Segment . TL.fromStrict
+  {-# INLINE segment #-}
+
+-- |
+-- @
+-- x :: 'String' == 'TL.unpack' ('unSegment' ('segment' x))
+-- @
+instance ToSegment String where
+  segment = Segment . TL.pack
+  {-# INLINE segment #-}
+
 --------------------------------------------------------------------------------
 
 -- | An attribute key (see 'Attr').
@@ -167,23 +242,19 @@
 -- \"foo\" :: 'Key'
 -- @
 --
--- Otherwise, you can use 'fromString' or the 'key' function.
+-- Otherwise, you can use 'fromString' or 'key'.
 --
 -- Notice that @\"\" :: 'Key'@ is acceptable, and will be correctly rendered and
 -- parsed back.
 newtype Key = Key TL.Text
   deriving (Eq, Show)
 
-key :: TL.Text -> Key
-key = Key
-{-# INLINE key #-}
-
 unKey :: Key -> TL.Text
 unKey = \(Key x) -> x
 {-# INLINE unKey #-}
 
 instance IsString Key where
-  fromString = key . TL.pack
+  fromString = key
   {-# INLINE fromString #-}
 
 instance Semigroup Key where
@@ -196,6 +267,46 @@
   mappend (Key a) (Key b) = Key (mappend a b)
   {-# INLINE mappend #-}
 
+-- | Convert an arbitrary type to a 'Key'.
+--
+-- You are encouraged to create custom 'ToKey' instances for your types
+-- making sure you avoid rendering sensitive details such as passwords, so that
+-- they don't accidentally end up in logs.
+--
+-- Any characters that need to be escaped for rendering will be automatically
+-- escaped at rendering time. You don't need to escape them here.
+class ToKey a where
+  key :: a -> Key
+
+-- | Identity.
+instance ToKey Key where
+  key = id
+  {-# INLINE key #-}
+
+-- |
+-- @
+-- x :: 'TL.Text' == 'unKey' ('key' x)
+-- @
+instance ToKey TL.Text where
+  key = Key
+  {-# INLINE key #-}
+
+-- |
+-- @
+-- x :: 'T.Text' == 'TL.toStrict' ('unKey' ('key' x))
+-- @
+instance ToKey T.Text where
+  key = Key . TL.fromStrict
+  {-# INLINE key #-}
+
+-- |
+-- @
+-- x :: 'String' == 'TL.unpack' ('unKey' ('key' x))
+-- @
+instance ToKey String where
+  key = Key . TL.pack
+  {-# INLINE key #-}
+
 --------------------------------------------------------------------------------
 
 -- | An attribute value (see 'Attr').
@@ -207,7 +318,7 @@
 -- \"foo\" :: 'Value'
 -- @
 --
--- Otherwise, you can use 'fromString' or the 'value' function.
+-- Otherwise, you can use 'fromString' or 'value'.
 --
 -- Notice that @\"\" :: 'Value'@ is acceptable, and will be correctly rendered
 -- and parsed back.
@@ -218,12 +329,8 @@
 unValue = \(Value x) -> x
 {-# INLINE unValue #-}
 
-value :: TL.Text -> Value
-value = Value
-{-# INLINE value #-}
-
 instance IsString Value where
-  fromString = value . TL.pack
+  fromString = value
   {-# INLINE fromString #-}
 
 instance Semigroup Value where
@@ -235,6 +342,46 @@
   {-# INLINE mempty #-}
   mappend (Value a) (Value b) = Value (mappend a b)
   {-# INLINE mappend #-}
+
+-- | Convert an arbitrary type to a 'Value'.
+--
+-- You are encouraged to create custom 'ToValue' instances for your types
+-- making sure you avoid rendering sensitive details such as passwords, so that
+-- they don't accidentally end up in logs.
+--
+-- Any characters that need to be escaped for rendering will be automatically
+-- escaped at rendering time. You don't need to escape them here.
+class ToValue a where
+  value :: a -> Value
+
+-- | Identity.
+instance ToValue Value where
+  value = id
+  {-# INLINE value #-}
+
+-- |
+-- @
+-- x :: 'TL.Text' == 'unValue' ('value' x)
+-- @
+instance ToValue TL.Text where
+  value = Value
+  {-# INLINE value #-}
+
+-- |
+-- @
+-- x :: 'T.Text' == 'TL.toStrict' ('unValue' ('value' x))
+-- @
+instance ToValue T.Text where
+  value = Value . TL.fromStrict
+  {-# INLINE value #-}
+
+-- |
+-- @
+-- x :: 'String' == 'TL.unpack' ('unValue' ('value' x))
+-- @
+instance ToValue String where
+  value = Value . TL.pack
+  {-# INLINE value #-}
 
 --------------------------------------------------------------------------------
 
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -61,27 +61,19 @@
 
 instance QC.Arbitrary Df1.Segment where
   arbitrary = fromString <$> QC.arbitrary
-  shrink = map Df1.segment . QC.shrink . Df1.unSegment
+  shrink = map fromString . QC.shrink . TL.unpack . Df1.unSegment
 
 instance QC.Arbitrary Df1.Key where
   arbitrary = fromString <$> QC.arbitrary
-  shrink = map Df1.key . QC.shrink . Df1.unKey
+  shrink = map fromString . QC.shrink . TL.unpack . Df1.unKey
 
 instance QC.Arbitrary Df1.Value where
   arbitrary = fromString <$> QC.arbitrary
-  shrink = map Df1.value . QC.shrink . Df1.unValue
+  shrink = map fromString . QC.shrink . TL.unpack . Df1.unValue
 
 instance QC.Arbitrary Df1.Message where
   arbitrary = fromString <$> QC.arbitrary
-  shrink = map Df1.message . QC.shrink . Df1.unMessage
-
-instance QC.Arbitrary T.Text where
-  arbitrary = T.pack <$> QC.arbitrary
-  shrink = map T.pack . QC.shrink . T.unpack
-
-instance QC.Arbitrary TL.Text where
-  arbitrary = TL.pack <$> QC.arbitrary
-  shrink = map TL.pack . QC.shrink . TL.unpack
+  shrink = map fromString . QC.shrink . TL.unpack . Df1.unMessage
 
 genSystemTime :: QC.Gen Time.SystemTime
 genSystemTime = do
